pax_global_header00006660000000000000000000000064127323111140014505gustar00rootroot0000000000000052 comment=0979a4b48ccec520e7f5fdd208adf7ace91c274a mongo-cxx-driver-legacy-1.1.2/000077500000000000000000000000001273231111400161605ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/.gitignore000066400000000000000000000002051273231111400201450ustar00rootroot00000000000000 # Directories that are generated /build /docs /callgrind.out.* /massif.out.* *~ *.pyc *# .#* #osx .DS_Store ._.DS_Store *.fuse_* mongo-cxx-driver-legacy-1.1.2/.mci.yml000066400000000000000000000565301273231111400175420ustar00rootroot00000000000000####################################### # CXX Driver Config for MCI # ####################################### ## Some variables for convenience: cxx_driver_variables: ## The basic set of tests to run on most buildvariants latest_test_list: &latest_tests - name: "compile" - name: "unit-test" - name: "integration-test-latest" - name: "integration-test-latest-with-auth" - name: "client-test-latest" ## Note that the in 3.0, the default storage engine is MMAPv1 and ## WiredTiger is opt-in, but as of MongoDB 3.1.4, the ## default is WiredTiger and MMAPv1 is opt-in. storage_engine_test_list: &storage_engine_tests - name: "compile" - name: "unit-test" - name: "integration-test-3.0" - name: "integration-test-3.0-with-WiredTiger" - name: "integration-test-3.2" - name: "integration-test-3.2-with-MMAPv1" - name: "client-test-3.0" - name: "client-test-3.0-with-WiredTiger" - name: "client-test-3.2" - name: "client-test-3.2-with-MMAPv1" version_test_list: &version_tests - name: "compile" - name: "lint" - name: "unit-test" - name: "integration-test-2.2" - name: "integration-test-2.4" - name: "integration-test-2.6" - name: "integration-test-3.0" - name: "integration-test-3.2" - name: "integration-test-latest" - name: "client-test-2.2" - name: "client-test-2.4" - name: "client-test-2.6" - name: "client-test-3.0" - name: "client-test-3.2" - name: "client-test-latest" ## Common download urls (merge in as hashes) mongo_download_url_prefixes: ubuntu1404: &mongo_url_ubuntu1404 mongo_url_prefix: "http://downloads.mongodb.com/linux/mongodb-linux-x86_64-" mongo_url_platform: "ubuntu1404-" windows64-bitcomm: &mongo_url_windows64 mongo_url_prefix: "http://downloads.mongodb.com/win32/mongodb-win32-x86_64-" mongo_url_platform: "windows-64-" windows32: &mongo_url_windows32 mongo_url_prefix: "http://downloads.mongodb.org/win32/mongodb-win32-i386-" mongo_url_enterprise_keyword: "" rhel55: &mongo_url_rhel55 mongo_url_prefix: "http://downloads.mongodb.com/linux/mongodb-linux-x86_64-" mongo_url_platform: "rhel57-" rhel55_32: &mongo_url_rhel55_32 mongo_url_prefix: "http://downloads.mongodb.org/linux/mongodb-linux-i686-" mongo_url_enterprise_keyword: "" mongo_url_subscription_keyword: "" osx-1010: &mongo_url_osx_1010 mongo_url_prefix: "http://downloads.mongodb.org/osx/mongodb-osx-x86_64-" mongo_url_enterprise_keyword: "" ## Common sets of scons flags scons_flags: standard: &scons_flags_64 scons_flags: "--64 --ssl --use-sasl-client --sharedclient" standard_32: &scons_flags_32 scons_flags: "--32 --ssl --use-sasl-client --sharedclient" ubuntu_c++11: &scons_flags_cpp11 scons_flags: "--64 --c++11 --ssl --use-sasl-client --sharedclient" osx_1010: &scons_flags_osx_1010 scons_flags: "--64 --ssl --use-sasl-client --sharedclient --osx-version-min=10.7 --libc++" ## test all plausible combinations of static/dynamic mongo client and windows runtime: static_windows: &scons_flags_64_windows_static scons_flags: "--64 --ssl --use-sasl-client" dynamic_RT_windows: &scons_flags_64_windows_dynamic_rt scons_flags: "--64 --ssl --use-sasl-client --dynamic-windows" dynamic_windows: &scons_flags_64_windows_dynamic scons_flags: "--64 --ssl --use-sasl-client --dynamic-windows --sharedclient" 32bit_windows: &scons_flags_32_windows_dynamic scons_flags: "--32 --dynamic-windows --sharedclient" ## Special compile flags compile_flags: debug: &compile_flags_debug compile_flags: "--dbg=on" parallel_compile_flags: proc_parallel: ¶llel_compile_flags_proc parallel_compile_flags: "-j$(grep -c ^processor /proc/cpuinfo)" sysctl_parallel: ¶llel_compile_flags_sysctl parallel_compile_flags: "-j$(sysctl -n hw.logicalcpu)" ## Scripts that are shared between buildvariants scripts: mongo_orchestration: windows: &mongo_orchestration_windows start_mongo_orchestration: | echo "Installing Mongo Orchestration..." trap 'set +o errexit; mongo-orchestration stop;' EXIT taskkill.exe /fi python /f echo "Starting Mongo Orchestration..." echo "{ \"releases\": { \"default\": \"c:\\\\mongodb\\\\bin\" }, \"last_updated\": \"2014-08-29 20:57:00.000000\" }" > orchestration.config mongo-orchestration -f orchestration.config -e default -s wsgiref start --socket-timeout-ms=60000 sleep 15 linux: &mongo_orchestration_linux ## we are going to manually install mongo-orchestration for now on Linux until it is stable enough that we don't always to install from HEAD start_mongo_orchestration: | echo "Installing Mongo Orchestration..." trap 'set +o errexit; mongo-orchestration stop;' EXIT echo "Starting Mongo Orchestration..." echo "{ \"releases\": { \"default\": \"`pwd`/mongodb/bin\" }, \"last_updated\": \"2014-08-29 20:57:00.000000\" }" > orchestration.config TMPDIR=/data/db mongo-orchestration -f orchestration.config -e default start --socket-timeout-ms=60000 sleep 15 osx: &mongo_orchestration_osx start_mongo_orchestration: | echo "Starting Mongo Orchestration..." trap 'set +o errexit; /usr/local/bin/mongo-orchestration stop;' EXIT echo "{ \"releases\": { \"default\": \"`pwd`/mongodb/bin\" }, \"last_updated\": \"2014-08-29 20:57:00.000000\" }" > orchestration.config TMPDIR=/data/db /usr/local/bin/mongo-orchestration -f orchestration.config -e default start # --socket-timeout-ms=60000 <- uncomment when OSX builders get new MO sleep 15 ## Other os-specific attributes, grouped by OS ## Misc. for Windows builds windows_compilers: ## msvc2010 msvc2010: &with_msvc2010 toolchain_flags: --msvc-version=10.0 libpath: --libpath="c:\local\boost_1_57_0\lib64-msvc-10.0" cpppath: --cpppath="c:\local\boost_1_57_0" dllpath: --runtime-library-search-path="c:\local\boost_1_57_0\lib64-msvc-10.0,c:\openssl\bin,c:\sasl\bin,c:\curl\dlls" extrapath: --extrapath="c:\openssl,c:\sasl,c:\curl" ## msvc2013, 32-bit boost headers msvc2013-32: &with_msvc2010_32bit toolchain_flags: --msvc-version=10.0 libpath: --libpath="c:\local\boost_1_57_0\lib32-msvc-10.0" cpppath: --cpppath="c:\local\boost_1_57_0" dllpath: --runtime-library-search-path="c:\local\boost_1_57_0\lib32-msvc-10.0,c:\curl\dlls" extrapath: --extrapath="c:\curl" msvc2013: &with_msvc2013 toolchain_flags: --msvc-version=12.0 libpath: --libpath="c:\local\boost_1_56_0\lib64-msvc-12.0" cpppath: --cpppath="c:\local\boost_1_56_0" dllpath: --runtime-library-search-path="c:\local\boost_1_56_0\lib64-msvc-12.0,c:\openssl\bin,c:\sasl\bin,c:\curl\dlls" extrapath: --extrapath="c:\openssl,c:\sasl,c:\curl" msvc2015: &with_msvc2015 toolchain_flags: --msvc-version=14.0 libpath: --libpath="c:\local\boost_1_60_0\lib64-msvc-14.0" cpppath: --cpppath="c:\local\boost_1_60_0" dllpath: --runtime-library-search-path="c:\local\boost_1_60_0\lib64-msvc-14.0,c:\openssl\bin,c:\sasl\bin,c:\curl\dlls" extrapath: --extrapath="c:\openssl,c:\sasl,c:\curl" ## all windows buildvariants have these attributes in common windows_common: &windows_common mongo_url_extension: "zip" scons: scons.bat extension: ".exe" windows: true <<: *mongo_orchestration_windows ## Paths for OS X builds osx_fixups: scons: boost_headers: &extrapath_osx_1010 extrapath: --extrapath="/usr/local" ## Paths and flags for RHEL 5.5 builds rhel55_fixups: scons: warning_flags: &warning_flags_rhel55 # For some reason GCC on RHEL 5.5 gives lots of warnings from its own headers when using # visibility attributes. warning_flags: --disable-warnings-as-errors cpp: cpp_boost: &cpppath_rhel55 cpppath: --cpppath="/usr/include/boost141" lib: lib32_boost: &libpath_rhel55_32 libpath: --libpath="/usr/lib/boost141" lib64_boost: &libpath_rhel55_64 libpath: --libpath="/usr/lib64/boost141" ####################################### # Functions # ####################################### functions: "fetch source" : command: git.get_project params: directory: mongo-cxx-driver "fetch mongodb" : command: shell.exec params: working_dir: "mongo-cxx-driver" script: | set -o verbose set -o errexit curl -s ${mongo_url} --output mongo_enterprise.${ext|tgz} ${decompress} mongo_enterprise.${ext|tgz} mv mongodb* mongodb chmod +x ./mongodb/bin/mongod${extension} if [ ${windows|false} = true ]; then cp -r mongodb /cygdrive/c/mongodb #This won't run on a 32bit OS. ./mongodb/bin/vcredist_x64${extension} /Q fi "fetch artifacts" : command: s3.get params: aws_key: ${aws_key} aws_secret: ${aws_secret} remote_file: mongo-cxx-driver/${build_variant}/${revision}/artifacts/mongo-${build_id}.tar.gz bucket: mciuploads extract_to: mongo-cxx-driver "use WiredTiger storage" : command: expansions.update params: updates: - key: "orchestration_preset" value: "--mongo-orchestration-preset=wiredtiger.json" "use MMAPv1 storage" : command: expansions.update params: updates: - key: "orchestration_preset" # Requires mongo-orchestration 0.4 value: "--mongo-orchestration-preset=mmapv1.json" "use auth" : command: expansions.update params: updates: - key: "orchestration_preset" # Requires mongo-orchestration 0.4.2 value: "--mongo-orchestration-preset=auth.json" "set version 2.2" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_subscription_keyword|subscription-}${mongo_url_platform|}2.2.7.${mongo_url_extension|tgz} "set version 2.4" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_subscription_keyword|subscription-}${mongo_url_platform|}2.4.14.${mongo_url_extension|tgz} "set version 2.6" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_enterprise_keyword|enterprise-}${mongo_url_platform|}2.6.12.${mongo_url_extension|tgz} "set version 3.0" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_enterprise_keyword|enterprise-}${mongo_url_platform|}3.0.11.${mongo_url_extension|tgz} "set version 3.2" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_enterprise_keyword|enterprise-}${mongo_url_platform|}3.2.5.${mongo_url_extension|tgz} "set version latest" : command: expansions.update params: updates: - key: "mongo_url" value: ${mongo_url_prefix}${mongo_url_enterprise_keyword|"enterprise-"}${mongo_url_platform|}latest.${mongo_url_extension|tgz} "run integration tests" : command: shell.exec params: working_dir: "mongo-cxx-driver" script: | ${start_mongo_orchestration} ${scons|scons} ${scons_flags} ${warning_flags} ${compile_flags} ${toolchain_flags} ${extrapath} ${dllpath} ${cpppath} ${libpath} ${orchestration_preset} integration "run client tests" : command: shell.exec params: working_dir: "mongo-cxx-driver" script: | ${start_mongo_orchestration} ${scons|scons} ${scons_flags} ${warning_flags} ${compile_flags} ${toolchain_flags} ${extrapath} ${dllpath} ${cpppath} ${libpath} ${orchestration_preset} examples pre: - command: expansions.fetch params: keys: - local_key: "aws_key" remote_key: "project_aws_key" - local_key: "aws_secret" remote_key: "project_aws_secret" - command: shell.exec params: script: | rm -rf "mongo-cxx-driver" if [ ! -e /data/db ]; then mkdir /data/db elif [ ! -d /data/db ]; then echo "/data/db already exists and is not a directory!" exit 1 fi post: - command: shell.exec params: script: | cd mongo-cxx-driver && mongo-orchestration stop ${killall_mci|pkill -9 mongo-orchestration; pkill -9 mongod; pkill -9 mongos;} ####################################### # Tasks # ####################################### tasks: - name: lint commands: - func: "fetch source" - command: git.apply_patch params: directory: "mongo-cxx-driver" - command: shell.exec params: working_dir: "mongo-cxx-driver" script: | set -o errexit set -o verbose ${scons|scons} ${scons_flags} ${warning_flags} ${compile_flags} ${toolchain_flags} ${extrapath} ${dllpath} ${cpppath} ${libpath} lint - name: compile commands: - func: "fetch source" - command: git.apply_patch params: directory: "mongo-cxx-driver" - command: shell.exec params: working_dir: "mongo-cxx-driver" script: | set -o errexit set -o verbose ${scons|scons} ${scons_flags} ${warning_flags} ${compile_flags} ${parallel_compile_flags} ${toolchain_flags} ${extrapath} ${dllpath} ${cpppath} ${libpath} ${compile_target|all check-install} - command: shell.exec params: working_dir: "mongo-cxx-driver" script: | set -o errexit set -o verbose tar -czf ../mongo-cxx-driver.tar.gz . - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: mongo-cxx-driver.tar.gz remote_file: mongo-cxx-driver/${build_variant}/${revision}/artifacts/mongo-${build_id}.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} - name: "unit-test" depends_on: - name: "compile" commands: - func: "fetch artifacts" - command: shell.exec params: working_dir: "mongo-cxx-driver" script: | set -o verbose ${scons|scons} ${scons_flags} ${warning_flags} ${compile_flags} ${toolchain_flags} ${extrapath} ${dllpath} ${cpppath} ${libpath} unit - name: "integration-test-2.2" depends_on: - name: "compile" commands: - func: "set version 2.2" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.4" depends_on: - name: "compile" commands: - func: "set version 2.4" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-2.6" depends_on: - name: "compile" commands: - func: "set version 2.6" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.0-with-WiredTiger" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "use WiredTiger storage" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.2" depends_on: - name: "compile" commands: - func: "set version 3.2" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-3.2-with-MMAPv1" depends_on: - name: "compile" commands: - func: "set version 3.2" - func: "use MMAPv1 storage" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest" depends_on: - name: "compile" commands: - func: "set version latest" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run integration tests" - name: "integration-test-latest-with-auth" depends_on: - name: "compile" commands: - func: "set version latest" - func: "fetch artifacts" - func: "use auth" - func: "fetch mongodb" - func: "run integration tests" - name: "client-test-2.2" depends_on: - name: "compile" commands: - func: "set version 2.2" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-2.4" depends_on: - name: "compile" commands: - func: "set version 2.4" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-2.6" depends_on: - name: "compile" commands: - func: "set version 2.6" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-3.0" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-3.0-with-WiredTiger" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "use WiredTiger storage" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-3.2" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-3.2-with-MMAPv1" depends_on: - name: "compile" commands: - func: "set version 3.0" - func: "use MMAPv1 storage" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" - name: "client-test-latest" depends_on: - name: "compile" commands: - func: "set version latest" - func: "fetch artifacts" - func: "fetch mongodb" - func: "run client tests" ####################################### # Buildvariants # ####################################### buildvariants: ####################################### # Linux Buildvariants # ####################################### ## RHEL 5.5 - name: rhel55 display_name: "RHEL 5.5" expansions: <<: *scons_flags_64 <<: *parallel_compile_flags_proc <<: *warning_flags_rhel55 <<: *cpppath_rhel55 <<: *libpath_rhel55_64 <<: *mongo_url_rhel55 <<: *mongo_orchestration_linux run_on: - rhel55-test tasks: *version_tests ## RHEL 5.5 32-bit - name: rhel55-32-bit display_name: "RHEL 5.5 32-bit" expansions: <<: *scons_flags_32 <<: *parallel_compile_flags_proc <<: *warning_flags_rhel55 <<: *cpppath_rhel55 <<: *libpath_rhel55_32 <<: *mongo_url_rhel55_32 <<: *mongo_orchestration_linux run_on: - rhel55-test tasks: *latest_tests ## Ubuntu 1404 - name: ubuntu1404 display_name: "Ubuntu1404" expansions: <<: *scons_flags_64 <<: *parallel_compile_flags_proc <<: *mongo_url_ubuntu1404 <<: *mongo_orchestration_linux run_on: - ubuntu1404-test tasks: *storage_engine_tests ## Ubuntu 1404 DEBUG - name: ubuntu1404-debug display_name: "Ubuntu1404 dbg" expansions: <<: *compile_flags_debug <<: *parallel_compile_flags_proc <<: *scons_flags_64 <<: *mongo_url_ubuntu1404 <<: *mongo_orchestration_linux run_on: - ubuntu1404-test tasks: *latest_tests ## Ubuntu 1404 C++11 - name: ubuntu1404-cpp11 display_name: "Ubuntu1404 C++11" expansions: <<: *scons_flags_cpp11 <<: *parallel_compile_flags_proc <<: *mongo_url_ubuntu1404 <<: *mongo_orchestration_linux run_on: - ubuntu1404-test tasks: *latest_tests ####################################### # OS X Buildvariants # ####################################### ## OS X 10.8 - name: os-x-107 display_name: "OS X 10.7" expansions: <<: *mongo_url_osx_1010 <<: *scons_flags_osx_1010 <<: *parallel_compile_flags_sysctl <<: *extrapath_osx_1010 <<: *mongo_orchestration_osx run_on: - osx-1010 tasks: *latest_tests ####################################### # Windows Buildvariants # ####################################### ## Windows 32-bit (msvc2010) ## dynamic client and RT - name: windows-32-msvc2010-dyn-dyn display_name: "Win32(2010) dyn-dyn" expansions: <<: *windows_common <<: *scons_flags_32_windows_dynamic <<: *parallel_compile_flags_proc <<: *mongo_url_windows32 <<: *with_msvc2010_32bit compile_target: driver build-unit run_on: - windows-64-vs2010-compile tasks: - name: "compile" - name: "unit-test" ## Windows 64-bit (msvc2010) ## static client and RT - name: windows-64-msvc2010-static-static display_name: "Win64(2010) static-static" expansions: <<: *windows_common <<: *scons_flags_64_windows_static <<: *parallel_compile_flags_proc <<: *mongo_url_windows64 <<: *with_msvc2010 run_on: - windows-64-vs2010-compile tasks: *latest_tests ## Windows 64-bit DEBUG DYNAMIC (msvc2010) ## dynamic client and RT - name: windows-64-msvc2010-dbg-dyn-dyn display_name: "Win64(2010) dbg dyn-dyn" expansions: <<: *windows_common <<: *compile_flags_debug <<: *parallel_compile_flags_proc <<: *scons_flags_64_windows_dynamic <<: *mongo_url_windows64 <<: *with_msvc2010 run_on: - windows-64-vs2010-compile tasks: *latest_tests ## Windows 64-bit DYNAMIC (msvc2013) ## dynamic client and RT - name: windows-64-msvc2013-dyn-dyn display_name: "Win64(2013) dyn-dyn" expansions: <<: *windows_common <<: *parallel_compile_flags_proc <<: *scons_flags_64_windows_dynamic <<: *mongo_url_windows64 <<: *with_msvc2013 run_on: - windows-64-vs2013-compile tasks: *latest_tests ## Windows 64-bit (msvc2013) DYNAMIC-RT ## static client, dynamic RT - name: windows-64-msvc-2013-static-dyn display_name: "Win64(2013) static-dyn" expansions: <<: *windows_common <<: *parallel_compile_flags_proc <<: *scons_flags_64_windows_dynamic_rt <<: *mongo_url_windows64 <<: *with_msvc2013 run_on: - windows-64-vs2013-compile tasks: *latest_tests ## Windows 64-bit DYNAMIC (msvc2015) ## dynamic client and RT - name: windows-64-msvc2015-dyn-dyn display_name: "Win64(2015) dyn-dyn" expansions: <<: *windows_common <<: *parallel_compile_flags_proc <<: *scons_flags_64_windows_dynamic <<: *mongo_url_windows64 <<: *with_msvc2015 run_on: - windows-64-vs2015-compile tasks: *latest_tests mongo-cxx-driver-legacy-1.1.2/.travis.yml000066400000000000000000000053031273231111400202720ustar00rootroot00000000000000language: cpp compiler: - gcc - clang env: global: - MONGO_REPO="http://repo.mongodb.com/apt/ubuntu" - REPO_TYPE="precise/mongodb-enterprise/2.6 multiverse" - SOURCES_LOC="/etc/apt/sources.list.d/mongodb-enterprise.list" - KEY_SERVER="hkp://keyserver.ubuntu.com:80" - MONGOD_PARAMS="--setParameter=enableTestCommands=1" - MONGOD_OPTS="--port 27999 --httpinterface --dbpath ./data --fork --logpath mongod.log ${MONGOD_PARAMS}" matrix: - SANITIZE= DEBUG= - SANITIZE= DEBUG=--dbg=on - SANITIZE=--sanitize=address --llvm-symbolizer=llvm-symbolizer-3.4 DEBUG=--dbg=on - SANITIZE=--sanitize=undefined DEBUG=--dbg=on matrix: exclude: - compiler: gcc env: SANITIZE=--sanitize=undefined DEBUG=--dbg=on # Setup required repositories before installation before_install: # GCC 4.8.1 - if [ "$CXX" == "g++" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi # Clang 3.4 - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi # Boost 1.49 - sudo add-apt-repository -y ppa:jkeiren/ppa # MongoDB Enterprise Edition 2.6 - sudo apt-key adv --keyserver ${KEY_SERVER} --recv 7F0CEB10 - echo "deb ${MONGO_REPO} ${REPO_TYPE}" | sudo tee ${SOURCES_LOC} # Update all the repositories - sudo apt-get update -qq install: # GCC 4.8.1 - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; fi - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; export CC="gcc-4.8"; fi # Clang 3.4 - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.4; fi - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.4"; export CC="clang-3.4"; fi # Install Boost 1.49 dependencies via PPA - sudo apt-get install -qq libboost1.49-dev libboost-program-options1.49-dev libboost-filesystem1.49-dev libboost-thread1.49-dev libboost-regex1.49-dev # Install MongoDB Enterprise and let smoke drive - sudo apt-get install mongodb-enterprise-server before_script: # Set SCONS_FLAGS based on new $CXX and $CC - $CXX --version - export GTEST_PARAMS="--gtest-filter=-SASL*" - export SCONS_CONCURRENCY_FLAG="-j3" - export SCONS_FLAGS="--mute --ssl --use-sasl-client $GTEST_PARAMS --cxx=$CXX --cc=$CC $DEBUG $SANITIZE" # Run lint - scons $SCONS_FLAGS lint # Build all targets - scons $SCONS_FLAGS $SCONS_CONCURRENCY_FLAG all # Install the driver - scons $SCONS_FLAGS $SCONS_CONCURRENCY_FLAG install # Check the installation - scons $SCONS_FLAGS check-install # Start Mongo Orchestration - mongod --version script: # Test the driver - scons $SCONS_FLAGS unit mongo-cxx-driver-legacy-1.1.2/.ycm_extra_conf.py000066400000000000000000000134041273231111400216120ustar00rootroot00000000000000# This file is NOT licensed under the GPLv3, which is the license for the rest # of YouCompleteMe. # # Here's the license text for this file: # # This is free and unencumbered software released into the public domain. # # Anyone is free to copy, modify, publish, use, compile, sell, or # distribute this software, either in source code form or as a compiled # binary, for any purpose, commercial or non-commercial, and by any # means. # # In jurisdictions that recognize copyright laws, the author or authors # of this software dedicate any and all copyright interest in the # software to the public domain. We make this dedication for the benefit # of the public at large and to the detriment of our heirs and # successors. We intend this dedication to be an overt act of # relinquishment in perpetuity of all present and future rights to this # software under copyright law. # # 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 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. # # For more information, please refer to import os import ycm_core # These are the compilation flags that will be used in case there's no # compilation database set (by default, one is not set). # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. flags = [ '-std=c++', '-x', 'c++', '-DBOOST_ALL_NO_LIB', '-D_SCONS', '-D_DEBUG', '-DMONGO_EXPOSE_MACROS', '-DSUPPORT_UTF8', '-D_FILE_OFFSET_BITS=64', '-DMONGO_HAVE___THREAD', '-DMONGO_HAVE_HEADER_UNISTD_H', '-DMONGO_HAVE_EXECINFO_BACKTRACE', '-DXP_UNIX', '-I.', '-I./src/', '-I./src/third_party', '-I./src/third_party/gtest-1.7.0/include', '-I./build/linux2/normal/', '-I./build/cached/', '-I./build/cached/mongo', '-isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1', '-Wall', '-Wextra', '-Wc++11-compat', '-Wno-long-long', '-Wno-variadic-macros', '-Wno-unknown-pragmas', '-Wno-unused-private-field', '-Wno-unused-parameter', '-Wsign-compare', '-Wmismatched-tags', '-Winvalid-pch', '-Wnon-virtual-dtor', '-Woverloaded-virtual', '-pipe' ] # Set this to the absolute path to the folder (NOT the file!) containing the # compile_commands.json file to use that instead of 'flags'. See here for # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html # # Most projects will NOT need to set this to anything; you can just change the # 'flags' list of compilation flags. Notice that YCM itself uses that approach. compilation_database_folder = '' if os.path.exists(compilation_database_folder): database = ycm_core.CompilationDatabase(compilation_database_folder) else: database = None SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm'] def DirectoryOfThisScript(): return os.path.dirname(os.path.abspath(__file__)) def MakeRelativePathsInFlagsAbsolute(flags, working_directory): if not working_directory: return list(flags) new_flags = [] make_next_absolute = False path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] for flag in flags: new_flag = flag if make_next_absolute: make_next_absolute = False if not flag.startswith('/'): new_flag = os.path.join(working_directory, flag) for path_flag in path_flags: if flag == path_flag: make_next_absolute = True break if flag.startswith(path_flag): path = flag[len(path_flag):] new_flag = path_flag + os.path.join(working_directory, path) break if new_flag: new_flags.append(new_flag) return new_flags def IsHeaderFile(filename): extension = os.path.splitext(filename)[1] return extension in ['.h', '.hxx', '.hpp', '.hh'] def GetCompilationInfoForFile(filename): # The compilation_commands.json file generated by CMake does not have # entries for header files. So we do our best by asking the db for flags # for a corresponding source file, if any. If one exists, the flags for # that file should be good enough. if IsHeaderFile(filename): basename = os.path.splitext(filename)[0] for extension in SOURCE_EXTENSIONS: replacement_file = basename + extension if os.path.exists(replacement_file): compilation_info = database.GetCompilationInfoForFile( replacement_file) if compilation_info.compiler_flags_: return compilation_info return None return database.GetCompilationInfoForFile(filename) def FlagsForFile(filename, **kwargs): if database: # Bear in mind that compilation_info.compiler_flags_ does NOT return a # python list, but a "list-like" StringVec object compilation_info = GetCompilationInfoForFile(filename) if not compilation_info: return None final_flags = MakeRelativePathsInFlagsAbsolute( compilation_info.compiler_flags_, compilation_info.compiler_working_dir_) try: final_flags.remove('-stdlib=libc++') except ValueError: pass else: relative_to = DirectoryOfThisScript() final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to) return { 'flags': final_flags, 'do_cache': True } mongo-cxx-driver-legacy-1.1.2/APACHE-2.0.txt000066400000000000000000000261361273231111400201470ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mongo-cxx-driver-legacy-1.1.2/CONTRIBUTING.md000066400000000000000000000073631273231111400204220ustar00rootroot00000000000000## Contributing to the MongoDB Legacy C++ Driver Project Pull requests are always welcome, and the MongoDB dev team appreciates any help the community can give to help make MongoDB better. For any particular improvement you want to make, you can begin a discussion on the [MongoDB Developers Forum][dev-forum]. This is the best place discuss your proposed improvement (and its implementation) with the core development team. [dev-forum]: https://groups.google.com/forum/?fromgroups#!forum/mongodb-dev "MongoDB Developers Forum" ## Getting Started - Create a [MongoDB JIRA account][jira-account]. - Create a [Github account][github-account]. - Fork the repository on Github at https://github.com/mongodb/mongo-cxx-driver. - Check out the 'legacy' branch 'git checkout legacy' [jira-account]: https://jira.mongodb.org/secure/Signup!default.jspa "MongoDB JIRA Signup" [github-account]: https://github.com/signup/free "Githup Signup" ## JIRA Tickets All commits to the C++ driver repository must reference an issue in the [CXX project][cxx-project] of the MongoDB JIRA. Before creating any new tickets, please search the existing backlog for any open tickets that represent your change request. If there is not one, then you should create a new ticket. Tickets specific to the legacy driver should be filed the label [legacy-cxx][legacy-cxx]. For bugs, please clearly describe the issue you are resolving, including the platforms on which the issue is present and clear steps to reproduce. For improvements or feature requests, be sure to explain the goal or use case and the approach your solution will take. [cxx-project]: https://jira.mongodb.org/browse/CXX [legacy-cxx]: https://jira.mongodb.org/browse/CXX-69?jql=labels%20%3D%20legacy-cxx ## The Life Cycle of a Pull Request Here's what happens when you submit a pull request: - The MongoDB engineering team will review your pull request to make sure you have included a CXX ticket in your request and signed the contributor agreement. - You should receive a response from one of our engineers with additional questions about your contributions. - If your pull request matches a ticket and is aligned with the Server Roadmap, it will get triaged and reviewed by the C++ driver and Kernel teams. - Pull requests that have been reviewed and approved will be signed off and merged into a development branch and the associated JIRA CXX issue will be resolved with an expected fixVersion. ## Style Guide All commits to the legacy branch must follow the [kernel development rules][kernel-dev-rules]. In particular, all code must follow the MongoDB [kernel code style guidelines][kernel-style-guide]. For anything not covered in this document you should default to the [Google CPP Style Guide][google-style-guide]. Your commit message should also be prefaced with the relevant JIRA ticket, e.g. "CXX-XXX Fixed a bug in aggregation". [kernel-dev-rules]: http://dochub.mongodb.org/core/kernelcodedevelopmentrules [kernel-style-guide]: http://dochub.mongodb.org/core/kernelcodestyle [google-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml ## Testing Every non-trivial change to the code base should be accompanied by a relevant addition to or modification of the test suite. If you don't believe this is necessary, please add an explanation in the JIRA ticket why no such changes are either needed or possible. All changes must also pass the full test suite (including your test additions/changes) on your local machine before you open a pull request. ## Contributor Agreement A patch will only be considered for merging into the upstream codebase after you have signed the [contributor agreement][contributor-agreement]. [contributor-agreement]: http://www.mongodb.com/contributor "MongoDB Contributor Agreement" mongo-cxx-driver-legacy-1.1.2/README.md000066400000000000000000000055161273231111400174460ustar00rootroot00000000000000# MongoDB C++ Driver [![Build Status](https://travis-ci.org/mongodb/mongo-cxx-driver.svg?branch=legacy)](https://travis-ci.org/mongodb/mongo-cxx-driver) Welcome to the MongoDB C++ Driver! Please see our [wiki page](https://github.com/mongodb/mongo-cxx-driver/wiki/Download-and-Compile-the-Legacy-Driver) for information about building, testing, and using the driver. Version [1.1.1](https://github.com/mongodb/mongo-cxx-driver/releases/tag/legacy-1.1.1) of the C++ legacy driver has been released. Please report any bugs or issues in the C++ [JIRA project](http://jira.mongodb.org/browse/CXX). You should only use the "legacy" branch if you had been previously using the "26compat" branch (or the driver inside of the server source) and want to benefit from incremental improvements while having the same overall API. > **Note:** As of MongoDB 2.6.0-rc1, it is no longer possible to build the driver from the server sources: this repository is the only approved source for C++ driver builds. ## Repository Overview | Branch | Stability | Development | Purpose | | -------- | ------------| ----------------- | ----------------------------------------------------- | | master | Stable | Stable Evolution | New C++11 driver | | legacy | Stable | Stable Evolution | Primary stable C++ driver release | | 26compat | Stable | Maintenance Only | Drop in replacement for users of existing 2.6 era C++ driver | Please note that stable branches are only production quality at stable release tags. Other commits or pre-release tags on a stable branch represent ongoing development work towards the next stable release, and therefore may be unstable. ## Components - `libmongoclient.[so|dylib|dll]` - The shared mongoclient library (but see notes) - `libmongoclient.a` - The static mongoclient library ## Building and Usage - [Download and Compile](https://github.com/mongodb/mongo-cxx-driver/wiki/Download%20and%20Compile) - [Tutorial](https://github.com/mongodb/mongo-cxx-driver/wiki/Tutorial) ## Bugs and Issues See http://jira.mongodb.org/browse/CXX ## Notes Use of the shared library is experimental on windows and is currently discouraged. This is primarily due to the complexity of ensuring a matching implementation of STL types between library and consumer code. This problem is unique to windows, as the consistent use of system libraries largely mitigates this danger. ## Documentation http://docs.mongodb.org/ecosystem/drivers/cpp/ ## Mailing Lists and IRC http://dochub.mongodb.org/core/community ## License The source files in this repository are made available under the terms of the Apache License, version 2.0. mongo-cxx-driver-legacy-1.1.2/SConstruct000066400000000000000000002166401273231111400202230ustar00rootroot00000000000000# -*- mode: python; -*- import copy import datetime import imp import os import platform as py_platform import re import shlex import shutil import stat import sys import textwrap import types import urllib import urllib2 import buildscripts.utils import buildscripts.docs import buildscripts.lint import buildscripts.clang_format EnsureSConsVersion( 1, 1, 0 ) def versiontuple(v): return tuple(map(int, (v.split(".")))) # --- platform identification --- # # This needs to precede the options section so that we can only offer some options on certain # platforms. platform = os.sys.platform nix = False linux = False darwin = False windows = False freebsd = False openbsd = False solaris = False if "darwin" == platform: darwin = True platform = "osx" # prettier than darwin elif platform.startswith("linux"): linux = True platform = "linux" elif "sunos5" == platform: solaris = True elif platform.startswith( "freebsd" ): freebsd = True elif platform.startswith( "openbsd" ): openbsd = True elif "win32" == platform: windows = True else: print( "No special config for [" + platform + "] which probably means it won't work" ) nix = not windows # --- options ---- use_clang = False options = {} def add_option( name, help, nargs, contributesToVariantDir, dest=None, default = None, type="string", choices=None, metavar=None, const=None ): if dest is None: dest = name if type == 'choice' and not metavar: metavar = '[' + '|'.join(choices) + ']' AddOption( "--" + name , dest=dest, type=type, nargs=nargs, action="store", choices=choices, default=default, metavar=metavar, const=const, help=help ) options[name] = { "help" : help , "nargs" : nargs , "contributesToVariantDir" : contributesToVariantDir , "dest" : dest, "default": default } def get_option( name ): return GetOption( name ) def has_option( name ): x = get_option( name ) if x is None: return False if x == False: return False if x == "": return False return True def get_variant_dir(): build_dir = get_option('build-dir').rstrip('/') if has_option('variant-dir'): return (build_dir + '/' + get_option('variant-dir')).rstrip('/') substitute = lambda x: re.sub( "[:,\\\\/]" , "_" , x ) a = [] for name in options: o = options[name] if not has_option( o["dest"] ): continue if not o["contributesToVariantDir"]: continue if get_option(o["dest"]) == o["default"]: continue if o["nargs"] == 0: a.append( name ) else: x = substitute( get_option( name ) ) a.append( name + "_" + x ) extras = [] if has_option("extra-variant-dirs"): extras = [substitute(x) for x in get_option( 'extra-variant-dirs' ).split( ',' )] if has_option("add-branch-to-variant-dir"): extras += ["branch_" + substitute( buildscripts.utils.getGitBranch() )] if has_option('cache'): s = "cached" s += "/".join(extras) + "/" else: s = "${PYSYSPLATFORM}/" a += extras if len(a) > 0: a.sort() s += "/".join( a ) + "/" else: s += "normal/" return (build_dir + '/' + s).rstrip('/') # build output add_option( "mute" , "do not display commandlines for compiling and linking, to reduce screen noise", 0, False ) # installation/packaging add_option( "prefix" , "installation prefix" , 1 , False, default='$BUILD_DIR/install' ) add_option( "extra-variant-dirs", "extra variant dir components, separated by commas", 1, False) add_option( "add-branch-to-variant-dir", "add current git branch to the variant dir", 0, False ) add_option( "build-dir", "build output directory", 1, False, default='#build') add_option( "variant-dir", "override variant subdirectory", 1, False ) add_option( "sharedclient", "build a libmongoclient.so/.dll" , 0 , False ) # linking options add_option( "release" , "release build" , 0 , True ) add_option( "lto", "enable link time optimizations (experimental, except with MSVC)" , 0 , True ) add_option( "dynamic-windows", "dynamically link on Windows", 0, True) add_option( "dynamic-boost", "dynamically link boost libraries on Windows", "?", True, type="choice", choices=["on", "off", "auto"], default="auto", const="on" ) add_option( "disable-declspec-thread", "don't use __declspec(thread) on Windows", 0, True) # base compile flags add_option( "64" , "whether to force 64 bit" , 0 , True , "force64" ) add_option( "32" , "whether to force 32 bit" , 0 , True , "force32" ) add_option( "endian" , "endianness of target platform" , 1 , False , "endian", type="choice", choices=["big", "little", "auto"], default="auto" ) add_option( "cxx", "compiler to use" , 1 , True ) add_option( "cc", "compiler to use for c" , 1 , True ) add_option( "cc-use-shell-environment", "use $CC from shell for C compiler" , 0 , False ) add_option( "cxx-use-shell-environment", "use $CXX from shell for C++ compiler" , 0 , False ) add_option( "c++11", "enable c++11 support (experimental)", "?", True, type="choice", choices=["on", "off", "auto"], const="on", default="off" ) add_option( "cpppath", "Include path if you have headers in a nonstandard directory" , 1 , False ) add_option( "libpath", "Library path if you have libraries in a nonstandard directory" , 1 , False ) add_option( "extrapath", "comma separated list of add'l paths (--extrapath /opt/foo/,/foo) static linking" , 1 , False ) add_option( "extralib", "comma separated list of libraries (--extralib js_static,readline" , 1 , False ) add_option("runtime-library-search-path", "comma separated list of dirs to append to PATH to find dynamic libs at runtime", 1, False) add_option( "ssl" , "Enable SSL" , 0 , True ) # library choices add_option( "libc++", "use libc++ (experimental, requires clang)", 0, True ) # new style debug and optimize flags add_option( "dbg", "Enable runtime debugging checks", "?", True, "dbg", type="choice", choices=["on", "off"], const="on" ) add_option( "opt", "Enable compile-time optimization", "?", True, "opt", type="choice", choices=["on", "off"], const="on" ) add_option( "sanitize", "enable selected sanitizers", 1, True, metavar="san1,san2,...sanN" ) add_option( "llvm-symbolizer", "name of (or path to) the LLVM symbolizer", 1, False, default="llvm-symbolizer" ) add_option( "gcov" , "compile with flags for gcov" , 0 , True ) add_option("use-sasl-client", "Support SASL authentication in the client library", 0, False) add_option('build-fast-and-loose', "NEVER for production builds", 0, False) add_option( "boost-lib-search-suffixes", "Comma delimited sequence of boost library suffixes to search", 1, False ) add_option('disable-warnings-as-errors', "Don't add -Werror to compiler command line", 0, False) add_option('propagate-shell-environment', "Pass shell environment to sub-processes (NEVER for production builds)", 0, False) add_option('gtest-filter', "Pass argument as filter to gtest", 1, False) add_option('mongo-orchestration-preset', "Pass argument to mongo-orchestration as the configuration preset", 1, False, default='basic.json' ) add_option('mongo-orchestration-host', "Host mongo-orchestration is running on", 1, False, default='localhost' ) add_option('mongo-orchestration-port', "Host mongo-orchestration is running on", 1, False, default='8889' ) add_option('variables-help', "Print the help text for SCons variables", 0, False) if darwin: add_option("osx-version-min", "minimum OS X version to support", 1, True) elif windows: win_version_min_choices = { 'xpsp3' : ('0501', '0300'), 'ws03sp2' : ('0502', '0200'), 'vista' : ('0600', '0000'), 'ws08r2' : ('0601', '0000'), 'win7' : ('0601', '0000'), 'win8' : ('0602', '0000'), } add_option("win-version-min", "minimum Windows version to support", 1, True, type = 'choice', default = None, choices = win_version_min_choices.keys()) # Someday get rid of --32 and --64 for windows and use these with a --msvc-target-arch flag # that mirrors msvc-host-arch. msvc_arch_choices = ['x86', 'i386', 'amd64', 'emt64', 'x86_64', 'ia64'] add_option("msvc-host-arch", "host architecture for ms toolchain", 1, True, type="choice", choices=msvc_arch_choices) add_option("msvc-script", "msvc toolchain setup script, pass no argument to suppress script execution", 1, True) add_option("msvc-version", "select msvc version", 1, True) add_option('cache', "Use an object cache rather than a per-build variant directory (experimental)", 0, False) add_option('cache-dir', "Specify the directory to use for caching objects if --cache is in use", 1, False, default="$BUILD_DIR/scons/cache") variable_parse_mode_choices=['auto', 'posix', 'other'] add_option('variable-parse-mode', "Select which parsing mode is used to interpret command line variables", 1, False, type='choice', default=variable_parse_mode_choices[0], choices=variable_parse_mode_choices) # Setup the command-line variables def variable_shlex_converter(val): parse_mode = get_option('variable-parse-mode') if parse_mode == 'auto': parse_mode = 'other' if windows else 'posix' return shlex.split(val, posix=(parse_mode == 'posix')) env_vars = Variables() env_vars.Add('ARFLAGS', help='Sets flags for the archiver', converter=variable_shlex_converter) env_vars.Add('CCFLAGS', help='Sets flags for the C and C++ compiler', converter=variable_shlex_converter) env_vars.Add('CFLAGS', help='Sets flags for the C compiler', converter=variable_shlex_converter) env_vars.Add('CPPDEFINES', help='Sets pre-processor definitions for C and C++', converter=variable_shlex_converter) env_vars.Add('CPPPATH', help='Adds paths to the preprocessor search path', converter=variable_shlex_converter) env_vars.Add('CXXFLAGS', help='Sets flags for the C++ compiler', converter=variable_shlex_converter) env_vars.Add('LIBPATH', help='Adds paths to the linker search path', converter=variable_shlex_converter) env_vars.Add('LIBS', help='Adds extra libraries to link against', converter=variable_shlex_converter) env_vars.Add('LINKFLAGS', help='Sets flags for the linker', converter=variable_shlex_converter) env_vars.Add('RPATH', help='Set the RPATH for dynamic libraries and executables', converter=variable_shlex_converter) env_vars.Add('SHCCFLAGS', help='Sets flags for the C and C++ compiler when building shared libraries', converter=variable_shlex_converter) env_vars.Add('SHCFLAGS', help='Sets flags for the C compiler when building shared libraries', converter=variable_shlex_converter) env_vars.Add('SHCXXFLAGS', help='Sets flags for the C++ compiler when building shared libraries', converter=variable_shlex_converter) env_vars.Add('SHLINKFLAGS', help='Sets flags for the linker when building shared libraries', converter=variable_shlex_converter) # don't run configure if user calls --help if GetOption('help'): Return() # --- environment setup --- # If the user isn't using the # to indicate top-of-tree or $ to expand a variable, forbid # relative paths. Relative paths don't really work as expected, because they end up relative to # the top level SConstruct, not the invokers CWD. We could in theory fix this with # GetLaunchDir, but that seems a step too far. buildDir = get_option('build-dir').rstrip('/') if buildDir[0] not in ['$', '#']: if not os.path.isabs(buildDir): print("Do not use relative paths with --build-dir") Exit(1) cacheDir = get_option('cache-dir').rstrip('/') if cacheDir[0] not in ['$', '#']: if not os.path.isabs(cacheDir): print("Do not use relative paths with --cache-dir") Exit(1) installDir = get_option('prefix').rstrip('/') if installDir[0] not in ['$', '#']: if not os.path.isabs(installDir): print("Do not use relative paths with --prefix") Exit(1) sconsDataDir = Dir(buildDir).Dir('scons') SConsignFile(str(sconsDataDir.File('sconsign'))) def printLocalInfo(): import sys, SCons print( "scons version: " + SCons.__version__ ) print( "python version: " + " ".join( [ `i` for i in sys.version_info ] ) ) printLocalInfo() boostLibs = [ "regex", "thread" , "system" ] linux64 = False force32 = has_option( "force32" ) force64 = has_option( "force64" ) if not force64 and not force32 and os.getcwd().endswith( "mongo-64" ): force64 = True print( "*** assuming you want a 64-bit build b/c of directory *** " ) msarch = None if force32: msarch = "x86" elif force64: msarch = "amd64" releaseBuild = has_option("release") # validate debug and optimization options dbg_opt_mapping = { # --dbg, --opt : dbg opt ( None, None ) : ( False, True ), ( None, "on" ) : ( False, True ), ( None, "off" ) : ( False, False ), ( "on", None ) : ( True, False ), # special case interaction ( "on", "on" ) : ( True, True ), ( "on", "off" ) : ( True, False ), ( "off", None ) : ( False, True ), ( "off", "on" ) : ( False, True ), ( "off", "off" ) : ( False, False ), } debugBuild, optBuild = dbg_opt_mapping[(get_option('dbg'), get_option('opt'))] if releaseBuild and (debugBuild or not optBuild): print("Error: A --release build may not have debugging, and must have optimization") Exit(1) mongoclientVersion = "1.1.2" # We don't keep the -pre in the user testable version identifiers, because # nobody should be conditioning on the pre-release status. mongoclientVersionComponents = re.split(r'\.|-rc', mongoclientVersion.partition('-pre')[0]) if len(mongoclientVersionComponents) not in (3,4): print("Error: client version most be of the form w.x.y[-rcz][-string]") Exit(1) # The Scons 'default' tool enables a lot of tools that we don't actually need to enable. # On platforms like Solaris, it actually does the wrong thing by enabling the sunstudio # toolchain first. As such it is simpler and more efficient to manually load the precise # set of tools we need for each platform. # If we aren't on a platform where we know the minimal set of tools, we fallback to loading # the 'default' tool. def decide_platform_tools(): if windows: # we only support MS toolchain on windows return ['msvc', 'mslink', 'mslib'] elif linux: return ['gcc', 'g++', 'gnulink', 'ar'] elif solaris: return ['gcc', 'g++', 'gnulink', 'ar'] elif darwin: return ['gcc', 'g++', 'applelink', 'ar'] else: return ["default"] tools = decide_platform_tools() + ["unittest", "integration_test", "textfile"] # We defer building the env until we have determined whether we want certain values. Some values # in the env actually have semantics for 'None' that differ from being absent, so it is better # to build it up via a dict, and then construct the Environment in one shot with kwargs. envDict = dict(BUILD_DIR=buildDir, VARIANT_DIR=get_variant_dir(), EXTRAPATH=get_option("extrapath"), PYTHON=File(buildscripts.utils.find_python()), tools=tools, PYSYSPLATFORM=os.sys.platform, CONFIGUREDIR=sconsDataDir.Dir('sconf_temp'), CONFIGURELOG=sconsDataDir.File('config.log'), MONGOCLIENT_VERSION=mongoclientVersion, MONGOCLIENT_VERSION_MAJOR=mongoclientVersionComponents[0], MONGOCLIENT_VERSION_MINOR=mongoclientVersionComponents[1], MONGOCLIENT_VERSION_PATCH=mongoclientVersionComponents[2], INSTALL_DIR=installDir, ) if windows: if msarch: envDict['TARGET_ARCH'] = msarch # We can't set this to None without disturbing the autodetection, # so only set it conditionally. if has_option('msvc-host-arch'): envDict['HOST_ARCH'] = get_option('msvc-host-arch') msvc_version = get_option('msvc-version') msvc_script = get_option('msvc-script') if msvc_version: if msvc_script: print("Passing --msvc-version with --msvc-script is not meaningful") Exit(1) envDict['MSVC_VERSION'] = msvc_version # The python None value is meaningful to MSVC_USE_SCRIPT; we want to interpret # --msvc-script= with no argument as meaning 'None', so check explicitly against None so # that '' is not interpreted as false. if msvc_script is not None: if has_option('msvc-host-arch'): print("Passing --msvc-host-arch with --msvc-script is not meaningful") Exit(1) if msarch: print("Passing --32 or --64 with --msvc-script is not meaningful") Exit(1) if msvc_script == "": msvc_script = None envDict['MSVC_USE_SCRIPT'] = msvc_script env = Environment(variables=env_vars, **envDict) del envDict def fatal_error(env, msg, *args): print msg.format(*args) Exit(1) def conf_error(env, msg, *args): print msg.format(*args) print "See {0} for details".format(env['CONFIGURELOG'].abspath) Exit(1) env.AddMethod(fatal_error, 'FatalError') env.AddMethod(conf_error, 'ConfError') if has_option('variables-help'): print env_vars.GenerateHelpText(env) Exit(0) unknown_vars = env_vars.UnknownVariables() if unknown_vars: env.FatalError("Unknown variables specified: {0}", ", ".join(unknown_vars.keys())) # Add any scons options that conflict with scons variables here. # The first item in each tuple is the option name and the second # is the variable name variable_conflicts = [ ('libpath', 'LIBPATH'), ('cpppath', 'CPPPATH'), ('extrapath', 'CPPPATH'), ('extrapath', 'LIBPATH'), ('extralib', 'LIBS') ] for (opt_name, var_name) in variable_conflicts: if has_option(opt_name) and var_name in env: env.FatalError("Both option \"--{0}\" and variable {1} were specified", opt_name, var_name) if has_option("cache"): EnsureSConsVersion( 2, 3, 0 ) if has_option("release"): env.FatalError( "Using the experimental --cache option is not permitted for --release builds") if has_option("gcov"): env.FatalError("Mixing --cache and --gcov doesn't work correctly yet. See SERVER-11084") env.CacheDir(str(env.Dir(cacheDir))) if has_option("propagate-shell-environment"): env['ENV'] = dict(os.environ); if has_option('runtime-library-search-path'): libs = get_option('runtime-library-search-path').split(',') envVar = None if windows: envVar = 'PATH' elif darwin: envVar = 'DYLD_LIBRARY_PATH' else: envVar = 'LD_LIBRARY_PATH' for lib in libs: env.AppendENVPath(envVar, env.Dir(lib), delete_existing=0) # Ignore fast-and-loose option if the scons cache is enabled (see SERVER-19088) if has_option('build-fast-and-loose') and not has_option('cache'): # See http://www.scons.org/wiki/GoFastButton for details env.Decider('MD5-timestamp') env.SetOption('max_drift', 1) env.SourceCode('.', None) if has_option('mute'): env.Append( CCCOMSTR = "Compiling $TARGET" ) env.Append( CXXCOMSTR = env["CCCOMSTR"] ) env.Append( SHCCCOMSTR = "Compiling $TARGET" ) env.Append( SHCXXCOMSTR = env["SHCCCOMSTR"] ) env.Append( LINKCOMSTR = "Linking $TARGET" ) env.Append( SHLINKCOMSTR = env["LINKCOMSTR"] ) env.Append( ARCOMSTR = "Generating library $TARGET" ) endian = get_option( "endian" ) if endian == "auto": endian = sys.byteorder if endian == "little": env["MONGO_BYTE_ORDER"] = "1234" elif endian == "big": env["MONGO_BYTE_ORDER"] = "4321" if env['PYSYSPLATFORM'] == 'linux3': env['PYSYSPLATFORM'] = 'linux2' if 'freebsd' in env['PYSYSPLATFORM']: env['PYSYSPLATFORM'] = 'freebsd' if os.sys.platform == 'win32': env['OS_FAMILY'] = 'win' else: env['OS_FAMILY'] = 'posix' if has_option( "cc-use-shell-environment" ) and has_option( "cc" ): env.FatalError("Cannot specify both --cc-use-shell-environment and --cc") elif has_option( "cxx-use-shell-environment" ) and has_option( "cxx" ): env.FatalError("Cannot specify both --cxx-use-shell-environment and --cxx") if has_option( "gtest-filter" ): env["gtest_filter"] = get_option('gtest-filter') if has_option( "cxx-use-shell-environment" ): env["CXX"] = os.getenv("CXX"); env["CC"] = env["CXX"] if has_option( "cc-use-shell-environment" ): env["CC"] = os.getenv("CC"); if has_option( "cxx" ): if not has_option( "cc" ): env.FatalError("Must specify C compiler when specifying C++ compiler") env["CXX"] = get_option( "cxx" ) if has_option( "cc" ): if not has_option( "cxx" ): env.FatalError("Must specify C++ compiler when specifying C compiler") env["CC"] = get_option( "cc" ) if has_option( "libpath" ): env["LIBPATH"] = [get_option( "libpath" )] if has_option( "cpppath" ): env["CPPPATH"] = [get_option( "cpppath" )] env.Prepend( CPPDEFINES=[ "MONGO_EXPOSE_MACROS" , ], CPPPATH=[ '$VARIANT_DIR', '$VARIANT_DIR/mongo' ] ) extraLibPlaces = [] env['EXTRACPPPATH'] = [] env['EXTRALIBPATH'] = [] def addExtraLibs( s ): for x in s.split(","): env.Append( EXTRACPPPATH=[ x + "/include" ] ) env.Append( EXTRALIBPATH=[ x + "/lib" ] ) extraLibPlaces.append( x + "/lib" ) if has_option( "extrapath" ): addExtraLibs( GetOption( "extrapath" ) ) if has_option( "extralib" ): for x in GetOption( "extralib" ).split( "," ): env.Append( LIBS=[ x ] ) # ---- other build setup ----- if "uname" in dir(os): processor = os.uname()[4] else: processor = "i386" if force32: processor = "i386" if force64: processor = "x86_64" env['PROCESSOR_ARCHITECTURE'] = processor nixLibPrefix = "lib" if darwin: pass elif linux: env.Append( LIBS=['m'] ) if os.uname()[4] == "x86_64" and not force32: linux64 = True nixLibPrefix = "lib64" env.Append( EXTRALIBPATH=["/usr/lib64" , "/lib64" ] ) env.Append( LIBS=["pthread"] ) force64 = False if force32: env.Append( EXTRALIBPATH=["/usr/lib32"] ) elif solaris: env.Append( CPPDEFINES=[ "__sunos__" ] ) env.Append( LIBS=["socket","resolv"] ) elif freebsd: env.Append( LIBS=[ "kvm" ] ) env.Append( EXTRACPPPATH=[ "/usr/local/include" ] ) env.Append( EXTRALIBPATH=[ "/usr/local/lib" ] ) env.Append( CPPDEFINES=[ "__freebsd__" ] ) env.Append( CCFLAGS=[ "-fno-omit-frame-pointer" ] ) elif openbsd: env.Append( EXTRACPPPATH=[ "/usr/local/include" ] ) env.Append( EXTRALIBPATH=[ "/usr/local/lib" ] ) env.Append( CPPDEFINES=[ "__openbsd__" ] ) elif windows: dynamicCRT = has_option("dynamic-windows") # Unless otherwise specified, link boost in the same manner as the CRT. dynamicBoost = get_option("dynamic-boost") if dynamicBoost == "auto": dynamicBoost = "on" if dynamicCRT else "off" if dynamicBoost == "on": env.Append( CPPDEFINES=[ "BOOST_ALL_DYN_LINK" ] ) if has_option("sharedclient") and not dynamicCRT: env.FatalError("The shared client must be built with the dynamic runtime library") # If tools configuration fails to set up 'cl' in the path, fall back to importing the whole # shell environment and hope for the best. This will work, for instance, if you have loaded # an SDK shell. for pathdir in env['ENV']['PATH'].split(os.pathsep): if os.path.exists(os.path.join(pathdir, 'cl.exe')): break else: print("NOTE: Tool configuration did not find 'cl' compiler, falling back to os environment") env['ENV'] = dict(os.environ) env.Append( CPPDEFINES=[ "_UNICODE" ] ) env.Append( CPPDEFINES=[ "UNICODE" ] ) env.Append( CPPDEFINES=[ "NOMINMAX" ] ) # /EHsc exception handling style for visual studio # /W3 warning level env.Append(CCFLAGS=["/EHsc","/W3"]) # some warnings we don't like: env.Append(CCFLAGS=[ # 'conversion' conversion from 'type1' to 'type2', possible loss of data # An integer type is converted to a smaller integer type. "/wd4244", # 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' # Typically some STL type isn't dllexport adorned, and we can't do anything about that "/wd4251", # 'var' : conversion from 'size_t' to 'type', possible loss of data When compiling with # /Wp64, or when compiling on a 64-bit operating system, type is 32 bits but size_t is # 64 bits when compiling for 64-bit targets. To fix this warning, use size_t instead of # a type "/wd4267", # non - DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' # Typically some base like noncopyable isn't dllexport adorned; nothing we can do "/wd4275", # C++ exception specification ignored except to indicate a function is not # __declspec(nothrow A function is declared using exception specification, which Visual # C++ accepts but does not implement "/wd4290", # 'this' : used in base member initializer list # The this pointer is valid only within nonstatic member functions. It cannot be # used in the initializer list for a base class. "/wd4355", # 'type' : forcing value to bool 'true' or 'false' (performance warning) # This warning is generated when a value that is not bool is assigned or coerced # into type bool. "/wd4800", # unknown pragma -- added so that we can specify unknown pragmas for other compilers "/wd4068", # On extremely old versions of MSVC (pre 2k5), default constructing an array member in a # constructor's initialization list would not zero the array members "in some cases". # since we don't target MSVC versions that old, this warning is safe to ignore. "/wd4351", ]) if not has_option("disable-warnings-as-errors"): env.Append( CCFLAGS=["/WX"], LINKFLAGS=["/WX"], ) env.Append( CPPDEFINES=[ "_CONSOLE", "_CRT_NONSTDC_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_CRT_SECURE_NO_DEPRECATE", "_SCL_SECURE_NO_WARNINGS", "_SCL_SECURE_NO_DEPRECATE", ] ) # this would be for pre-compiled headers, could play with it later #env.Append( CCFLAGS=['/Yu"pch.h"'] ) # docs say don't use /FD from command line (minimal rebuild) # /Gy function level linking (implicit when using /Z7) # /Z7 debug info goes into each individual .obj file -- no .pdb created env.Append( CCFLAGS= ["/Z7", "/errorReport:none"] ) # /DEBUG will tell the linker to create a .pdb file # which WinDbg and Visual Studio will use to resolve # symbols if you want to debug a release-mode image. # Note that this means we can't do parallel links in the build. # # Please also note that this has nothing to do with _DEBUG or optimization. env.Append( LINKFLAGS=["/DEBUG"] ) # /MD: use the multithreaded, DLL version of the run-time library (MSVCRT.lib/MSVCR###.DLL) # /MT: use the multithreaded, static version of the run-time library (LIBCMT.lib) # /MDd: Defines _DEBUG, _MT, _DLL, and uses MSVCRTD.lib/MSVCRD###.DLL # /MTd: Defines _DEBUG, _MT, and causes your application to use the # debug multithread version of the run-time library (LIBCMTD.lib) winRuntimeLibMap = { #dyn #dbg ( False, False ) : "/MT", ( False, True ) : "/MTd", ( True, False ) : "/MD", ( True, True ) : "/MDd", } env.Append(CCFLAGS=[winRuntimeLibMap[(dynamicCRT, debugBuild)]]) # With VS 2012 and later we need to specify 5.01 as the target console # so that our 32-bit builds run on Windows XP # See https://software.intel.com/en-us/articles/linking-applications-using-visual-studio-2012-to-run-on-windows-xp # if msarch == "x86": env.Append( LINKFLAGS=["/SUBSYSTEM:CONSOLE,5.01"]) if optBuild: # /O2: optimize for speed (as opposed to size) # /Oy-: disable frame pointer optimization (overrides /O2, only affects 32-bit) # /INCREMENTAL: NO - disable incremental link - avoid the level of indirection for function # calls env.Append( CCFLAGS=["/O2", "/Oy-"] ) env.Append( LINKFLAGS=["/INCREMENTAL:NO"]) else: env.Append( CCFLAGS=["/Od"] ) if debugBuild and not optBuild: # /RTC1: - Enable Stack Frame Run-Time Error Checking; Reports when a variable is used # without having been initialized (implies /Od: no optimizations) env.Append( CCFLAGS=["/RTC1"] ) env.Append(LIBS=[ 'ws2_32.lib', 'DbgHelp.lib' ]) if nix: # -Winvalid-pch Warn if a precompiled header (see Precompiled Headers) is found in the search path but can't be used. env.Append( CCFLAGS=["-fPIC", "-ggdb", "-pthread", "-Wall", "-Wsign-compare", "-Wno-unknown-pragmas", "-Winvalid-pch"] ) # env.Append( " -Wconversion" ) TODO: this doesn't really work yet if linux or darwin: env.Append( CCFLAGS=["-pipe"] ) if not has_option("disable-warnings-as-errors"): env.Append( CCFLAGS=["-Werror"] ) env.Append( CPPDEFINES=["_FILE_OFFSET_BITS=64"] ) env.Append( CXXFLAGS=["-Wnon-virtual-dtor", "-Woverloaded-virtual"] ) env.Append( LINKFLAGS=["-fPIC"] ) # SERVER-9761: Ensure early detection of missing symbols in dependent libraries at program # startup. # # TODO: Is it necessary to add to both linkflags and shlinkflags, or are LINKFLAGS # propagated to SHLINKFLAGS? if darwin: env.Append( LINKFLAGS=["-Wl,-bind_at_load"] ) env.Append( SHLINKFLAGS=["-Wl,-bind_at_load"] ) else: env.Append( LINKFLAGS=["-Wl,-z,now"] ) env.Append( SHLINKFLAGS=["-Wl,-z,now"] ) if not darwin: env.Append( LINKFLAGS=["-rdynamic"] ) env.Append( LIBS=[] ) # Allow colorized output env['ENV']['TERM'] = os.environ.get('TERM', None) if linux and has_option( "gcov" ): env.Append( CXXFLAGS=" -fprofile-arcs -ftest-coverage " ) env.Append( LINKFLAGS=" -fprofile-arcs -ftest-coverage " ) if optBuild: env.Append( CCFLAGS=["-O3"] ) else: env.Append( CCFLAGS=["-O0"] ) if debugBuild: if not optBuild: env.Append( CCFLAGS=["-fstack-protector"] ) env.Append( LINKFLAGS=["-fstack-protector"] ) env.Append( SHLINKFLAGS=["-fstack-protector"] ) if force64: env.Append( CCFLAGS="-m64" ) env.Append( LINKFLAGS="-m64" ) if force32: env.Append( CCFLAGS="-m32" ) env.Append( LINKFLAGS="-m32" ) if debugBuild: env.Append( CPPDEFINES=["MONGO_DEBUG_BUILD"] ); try: umask = os.umask(022) except OSError: pass env.Prepend(CPPPATH=['$VARIANT_DIR/third_party/gtest-1.7.0/include']) boostSuffixList = ["-mt", ""] if get_option("boost-lib-search-suffixes") is not None: boostSuffixList = get_option("boost-lib-search-suffixes") if boostSuffixList == "": boostSuffixList = [] else: boostSuffixList = boostSuffixList.split(',') env.Append( CPPPATH=['$EXTRACPPPATH'], LIBPATH=['$EXTRALIBPATH'] ) # --- check system --- def doConfigure(myenv): # Check that the compilers work. # # TODO: Currently, we have some flags already injected. Eventually, this should test the # bare compilers, and we should re-check at the very end that TryCompile and TryLink still # work with the flags we have selected. conf = Configure(myenv, help=False) if 'CheckCXX' in dir( conf ): if not conf.CheckCXX(): conf.env.FatalError("C++ compiler {0} does not work", conf.env["CXX"]) # Only do C checks if CC != CXX check_c = (myenv["CC"] != myenv["CXX"]) if check_c and 'CheckCC' in dir( conf ): if not conf.CheckCC(): conf.env.FatalError("C compiler {0} does not work", conf.env["CC"]) myenv = conf.Finish() # Identify the toolchain in use. We currently support the following: # TODO: Goes in the env? toolchain_gcc = "GCC" toolchain_clang = "clang" toolchain_msvc = "MSVC" def CheckForToolchain(context, toolchain, lang_name, compiler_var, source_suffix): test_bodies = { toolchain_gcc : ( # Clang also defines __GNUC__ """ #if !defined(__GNUC__) || defined(__clang__) #error #endif """), toolchain_clang : ( """ #if !defined(__clang__) #error #endif """), toolchain_msvc : ( """ #if !defined(_MSC_VER) #error #endif """), } print_tuple = (lang_name, context.env[compiler_var], toolchain) context.Message('Checking if %s compiler "%s" is %s... ' % print_tuple) # Strip indentation from the test body to ensure that the newline at the end of the # endif is the last character in the file (rather than a line of spaces with no # newline), and that all of the preprocessor directives start at column zero. Both of # these issues can trip up older toolchains. test_body = textwrap.dedent(test_bodies[toolchain]) result = context.TryCompile(test_body, source_suffix) context.Result(result) return result conf = Configure(myenv, help=False, custom_tests = { 'CheckForToolchain' : CheckForToolchain, }) toolchain = None have_toolchain = lambda: toolchain != None using_msvc = lambda: toolchain == toolchain_msvc using_gcc = lambda: toolchain == toolchain_gcc using_clang = lambda: toolchain == toolchain_clang if windows: toolchain_search_sequence = [toolchain_msvc] else: toolchain_search_sequence = [toolchain_gcc, toolchain_clang] for candidate_toolchain in toolchain_search_sequence: if conf.CheckForToolchain(candidate_toolchain, "C++", "CXX", ".cpp"): toolchain = candidate_toolchain break if not have_toolchain(): conf.env.FatalError("Couldn't identify the toolchain") if check_c and not conf.CheckForToolchain(toolchain, "C", "CC", ".c"): conf.env.FatalError("C toolchain doesn't match identified C++ toolchain") myenv = conf.Finish() global use_clang use_clang = using_clang() if using_gcc(): myenv.Append(LINKFLAGS=["-pthread"]) # Figure out what our minimum windows version is. If the user has specified, then use # that. Otherwise, if they have explicitly selected between 32 bit or 64 bit, choose XP or # Vista respectively. Finally, if they haven't done either of these, try invoking the # compiler to figure out whether we are doing a 32 or 64 bit build and select as # appropriate. if windows: win_version_min = None default_32_bit_min = 'xpsp3' default_64_bit_min = 'ws03sp2' if has_option('win-version-min'): win_version_min = get_option('win-version-min') else: if force32: win_version_min = default_32_bit_min elif force64: win_version_min = default_64_bit_min else: def CheckFor64Bit(context): win64_test_body = textwrap.dedent( """ #if !defined(_WIN64) #error #endif """ ) context.Message('Checking if toolchain is in 64-bit mode... ') result = context.TryCompile(win64_test_body, ".c") context.Result(result) return result conf = Configure(myenv, help=False, custom_tests = { 'CheckFor64Bit' : CheckFor64Bit }) if conf.CheckFor64Bit(): win_version_min = default_64_bit_min else: win_version_min = default_32_bit_min conf.Finish(); env['WIN_VERSION_MIN'] = win_version_min win_version_min = win_version_min_choices[win_version_min] env.Append( CPPDEFINES=[("_WIN32_WINNT", "0x" + win_version_min[0])] ) env.Append( CPPDEFINES=[("NTDDI_VERSION", "0x" + win_version_min[0] + win_version_min[1])] ) def AddFlagIfSupported(env, tool, extension, flag, **mutation): def CheckFlagTest(context, tool, extension, flag): test_body = "" context.Message('Checking if %s compiler supports %s... ' % (tool, flag)) ret = context.TryCompile(test_body, extension) context.Result(ret) return ret if using_msvc(): env.FatalError("AddFlagIfSupported is not currently supported with MSVC") test_mutation = mutation if using_gcc(): test_mutation = copy.deepcopy(mutation) # GCC helpfully doesn't issue a diagnostic on unknown flags of the form -Wno-xxx # unless other diagnostics are triggered. That makes it tough to check for support # for -Wno-xxx. To work around, if we see that we are testing for a flag of the # form -Wno-xxx (but not -Wno-error=xxx), we also add -Wxxx to the flags. GCC does # warn on unknown -Wxxx style flags, so this lets us probe for availablity of # -Wno-xxx. for kw in test_mutation.keys(): test_flags = test_mutation[kw] for test_flag in test_flags: if test_flag.startswith("-Wno-") and not test_flag.startswith("-Wno-error="): test_flags.append(re.sub("^-Wno-", "-W", test_flag)) cloned = env.Clone() cloned.Append(**test_mutation) # For GCC, we don't need anything since bad flags are already errors, but # adding -Werror won't hurt. For clang, bad flags are only warnings, so we need -Werror # to make them real errors. cloned.Append(CCFLAGS=['-Werror']) conf = Configure(cloned, help=False, custom_tests = { 'CheckFlag' : lambda(ctx) : CheckFlagTest(ctx, tool, extension, flag) }) available = conf.CheckFlag() conf.Finish() if available: env.Append(**mutation) return available def AddToCFLAGSIfSupported(env, flag): return AddFlagIfSupported(env, 'C', '.c', flag, CFLAGS=[flag]) def AddToCCFLAGSIfSupported(env, flag): return AddFlagIfSupported(env, 'C', '.c', flag, CCFLAGS=[flag]) def AddToCXXFLAGSIfSupported(env, flag): return AddFlagIfSupported(env, 'C++', '.cpp', flag, CXXFLAGS=[flag]) if using_gcc() or using_clang(): # This warning was added in g++-4.8. AddToCCFLAGSIfSupported(myenv, '-Wno-unused-local-typedefs') # Clang likes to warn about unused functions, which seems a tad aggressive and breaks # -Werror, which we want to be able to use. AddToCCFLAGSIfSupported(myenv, '-Wno-unused-function') # TODO: Note that the following two flags are added to CCFLAGS even though they are # really C++ specific. We need to do this because SCons passes CXXFLAGS *before* # CCFLAGS, but CCFLAGS contains -Wall, which re-enables the warnings we are trying to # suppress. In the future, we should move all warning flags to CCWARNFLAGS and # CXXWARNFLAGS and add these to CCOM and CXXCOM as appropriate. # # Clang likes to warn about unused private fields, but some of our third_party # libraries have such things. AddToCCFLAGSIfSupported(myenv, '-Wno-unused-private-field') # Prevents warning about using deprecated features (such as auto_ptr in c++11) # Using -Wno-error=deprecated-declarations does not seem to work on some compilers, # including at least g++-4.6. AddToCCFLAGSIfSupported(myenv, "-Wno-deprecated-declarations") # As of clang-3.4, this warning appears in v8, and gets escalated to an error. AddToCCFLAGSIfSupported(myenv, "-Wno-tautological-constant-out-of-range-compare") # New in clang-3.4, trips up things mostly in third_party, but in a few places in the # primary mongo sources as well. AddToCCFLAGSIfSupported(myenv, "-Wno-unused-const-variable") # This has been suppressed in gcc 4.8, due to false positives, but not in clang. So # we explicitly disable it here. AddToCCFLAGSIfSupported(myenv, "-Wno-missing-braces") # Check if we need to disable null-conversion warnings if using_clang(): def CheckNullConversion(context): test_body = """ #include struct TestType { int value; bool boolValue; }; bool foo() { boost::shared_ptr sp(new TestType); return NULL != sp; } """ context.Message('Checking if implicit boost::shared_ptr null conversion is supported... ') ret = context.TryCompile(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckNullConversion' : CheckNullConversion, }) if conf.CheckNullConversion() == False: env.Append( CCFLAGS="-Wno-null-conversion" ) conf.Finish() # This needs to happen before we check for libc++, since it affects whether libc++ is available. if darwin and has_option('osx-version-min'): min_version = get_option('osx-version-min') min_version_flag = '-mmacosx-version-min=%s' % (min_version) if not AddToCCFLAGSIfSupported(myenv, min_version_flag): myenv.ConfError("Can't set minimum OS X version with this compiler") myenv.AppendUnique(LINKFLAGS=[min_version_flag]) usingLibStdCxx = False if has_option('libc++'): if not using_clang(): myenv.ConfError('libc++ is currently only supported for clang') if darwin and has_option('osx-version-min') and versiontuple(min_version) < versiontuple('10.7'): print("Warning: You passed option 'libc++'. You probably want to also pass 'osx-version-min=10.7' or higher for libc++ support.") if AddToCXXFLAGSIfSupported(myenv, '-stdlib=libc++'): myenv.Append(LINKFLAGS=['-stdlib=libc++']) else: myenv.ConfError('libc++ requested, but compiler does not support -stdlib=libc++' ) else: def CheckLibStdCxx(context): test_body = """ #include #if !defined(__GLIBCXX__) #error #endif """ context.Message('Checking if we are using libstdc++... ') ret = context.TryCompile(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckLibStdCxx' : CheckLibStdCxx, }) usingLibStdCxx = conf.CheckLibStdCxx() conf.Finish() # Check to see if we are trying to use an elderly libstdc++, which we arbitrarily define as # 4.6.0. This is primarly to help people using clang in C++11 mode on OS X but forgetting # to use --libc++. We also use it to decide if we trust the libstdc++ debug mode. We would, # ideally, check the __GLIBCXX__ version, but for various reasons this is not # workable. Instead, we switch on the fact that _GLIBCXX_BEGIN_NAMESPACE_VERSION wasn't # introduced until libstdc++ 4.6.0. haveGoodLibStdCxx = False if usingLibStdCxx: def CheckModernLibStdCxx(context): test_body = """ #include #if !defined(_GLIBCXX_BEGIN_NAMESPACE_VERSION) #error libstdcxx older than 4.6.0 #endif """ context.Message('Checking for libstdc++ 4.6.0 or better... ') ret = context.TryCompile(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckModernLibStdCxx' : CheckModernLibStdCxx, }) haveGoodLibStdCxx = conf.CheckModernLibStdCxx() conf.Finish() # Sort out whether we can and should use C++11: cxx11_mode = get_option("c++11") if using_msvc(): if cxx11_mode == "off": print( 'WARNING: Cannot disable C++11 features when using MSVC' ) else: # If we are using libstdc++, only allow C++11 mode with our line-in-the-sand good # libstdc++. As always, if in auto mode fall back to disabling if we don't have a good # libstdc++, otherwise fail the build because we can't honor the explicit request. if cxx11_mode != "off" and usingLibStdCxx: if not haveGoodLibStdCxx: if cxx11_mode == "auto": cxx11_mode = "off" else: cxx11_error = 'Detected libstdc++ is too old to support C++11 mode' if darwin: cxx11_error += \ '\nTry building with --libc++ and --osx-version-min=10.7 or higher' myenv.ConfError(cxx11_error) # We are going to be adding flags to the environment, but we don't want to persist # those changes unless we pass all the below checks. Make a copy of the environment # that we will modify, we will only "commit" the changes to the env if we pass all the # checks. cxx11Env = myenv.Clone() # For our other compilers (gcc and clang) we need to pass -std=c++0x or -std=c++11, # but we prefer the latter. Try that first, and fall back to c++0x if we don't # detect that --std=c++11 works. If we can't find a flag and C++11 was explicitly # requested, error out, otherwise turn off C++11 support in auto mode. if cxx11_mode != "off": if not AddToCXXFLAGSIfSupported(cxx11Env, '-std=c++11'): if not AddToCXXFLAGSIfSupported(cxx11Env, '-std=c++0x'): if cxx11_mode == "auto": cxx11_mode = "off" else: cxx11Env.ConfError( 'C++11 mode requested, but cannot find a flag to enable it') # We appear to have C++11, or at least a flag to enable it, which is now set in the # environment. If we are in auto mode, check if the compiler claims that it strictly # supports C++11, and disable C++11 if not. If the user has explicitly requested C++11, # we don't care about what the compiler claims to support, trust the user. if cxx11_mode == "auto": def CheckCxx11Official(context): test_body = """ #if __cplusplus < 201103L #error #endif const int not_an_empty_file = 0; """ context.Message('Checking if __cplusplus >= 201103L to auto-enable C++11... ') ret = context.TryCompile(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(cxx11Env, help=False, custom_tests = { 'CheckCxx11Official' : CheckCxx11Official, }) if cxx11_mode == "auto" and not conf.CheckCxx11Official(): cxx11_mode = "off" conf.Finish() # We require c99 mode for C files when C++11 is enabled, so perform the same dance # as above: if C++11 mode is not off, try the flag, if we are in auto mode and we fail # then turn off C++11, otherwise C++11 was explicitly requested and we should error out. if cxx11_mode != "off": if not AddToCFLAGSIfSupported(cxx11Env, '-std=c99'): if cxx11_mode == "auto": cxx11_mode = "off" else: cxx11Env.ConfError( "C++11 mode selected for C++ files, but can't enable C99 for C files") # If we got here and cxx11_mode hasn't become false, then its true, so swap in the # modified environment. if cxx11_mode != "off": cxx11_mode = "on" myenv = cxx11Env # Check if we are on a POSIX system by testing if _POSIX_VERSION is defined. def CheckPosixSystem(context): test_body = """ // POSIX requires the existence of unistd.h, so if we can't include unistd.h, we // are definitely not a POSIX system. #include #if !defined(_POSIX_VERSION) #error not a POSIX system #endif """ context.Message('Checking if we are on a POSIX system... ') ret = context.TryCompile(textwrap.dedent(test_body), ".c") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckPosixSystem' : CheckPosixSystem, }) posix_system = conf.CheckPosixSystem() conf.Finish() # Check if we are on a system that support the POSIX clock_gettime function # and the "monotonic" clock. posix_monotonic_clock = False if posix_system: def CheckPosixMonotonicClock(context): test_body = """ #include #if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) #error POSIX clock_gettime not supported #elif !(defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) #error POSIX monotonic clock not supported #endif """ context.Message('Checking if the POSIX monotonic clock is supported... ') ret = context.TryCompile(textwrap.dedent(test_body), ".c") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckPosixMonotonicClock' : CheckPosixMonotonicClock, }) posix_monotonic_clock = conf.CheckPosixMonotonicClock() conf.Finish() if has_option('sanitize'): if not (using_clang() or using_gcc()): myenv.FatalError('sanitize is only supported with clang or gcc') sanitizer_list = get_option('sanitize').split(',') using_lsan = 'leak' in sanitizer_list using_asan = 'address' in sanitizer_list or using_lsan # If the user asked for leak sanitizer turn on the detect_leaks # ASAN_OPTION. If they asked for address sanitizer as well, drop # 'leak', because -fsanitize=leak means no address. # # --sanitize=leak: -fsanitize=leak, detect_leaks=1 # --sanitize=address,leak: -fsanitize=address, detect_leaks=1 # --sanitize=address: -fsanitize=address # if using_lsan: if using_asan: myenv['ENV']['ASAN_OPTIONS'] = "detect_leaks=1" myenv['ENV']['LSAN_OPTIONS'] = "suppressions=%s" % myenv.File("#etc/lsan.suppressions").abspath if 'address' in sanitizer_list: sanitizer_list.remove('leak') sanitizer_option = '-fsanitize=' + ','.join(sanitizer_list) if AddToCCFLAGSIfSupported(myenv, sanitizer_option): myenv.Append(LINKFLAGS=[sanitizer_option]) myenv.Append(CCFLAGS=['-fno-omit-frame-pointer']) else: myenv.ConfError('Failed to enable sanitizers with flag: {0}', sanitizer_option ) blackfiles_map = { "address" : myenv.File("#etc/asan.blacklist"), "leak" : myenv.File("#etc/asan.blacklist"), "thread" : myenv.File("#etc/tsan.blacklist"), "undefined" : myenv.File("#etc/ubsan.blacklist"), } blackfiles = set([v for (k, v) in blackfiles_map.iteritems() if k in sanitizer_list]) blacklist_options=["-fsanitize-blacklist=%s" % blackfile for blackfile in blackfiles] for blacklist_option in blacklist_options: if AddToCCFLAGSIfSupported(myenv, blacklist_option): myenv.Append(LINKFLAGS=[blacklist_option]) llvm_symbolizer = get_option('llvm-symbolizer') if os.path.isabs(llvm_symbolizer): if not myenv.File(llvm_symbolizer).exists(): print("WARNING: Specified symbolizer '%s' not found" % llvm_symbolizer) llvm_symbolizer = None else: llvm_symbolizer = myenv.WhereIs(llvm_symbolizer) if llvm_symbolizer: myenv['ENV']['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer myenv['ENV']['LSAN_SYMBOLIZER_PATH'] = llvm_symbolizer elif using_lsan: myenv.ConfError("Using the leak sanitizer requires a valid symbolizer") # When using msvc, check for VS 2013 Update 2+ so we can use new compiler flags if using_msvc(): haveVS2013Update2OrLater = False def CheckVS2013Update2(context): test_body = """ #if _MSC_VER < 1800 || (_MSC_VER == 1800 && _MSC_FULL_VER < 180030501) #error Old Version #endif int main(int argc, char* argv[]) { return 0; } """ context.Message('Checking for VS 2013 Update 2 or Later... ') ret = context.TryCompile(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckVS2013Update2' : CheckVS2013Update2, }) haveVS2013Update2OrLater = conf.CheckVS2013Update2() conf.Finish() if haveVS2013Update2OrLater and optBuild: # http://blogs.msdn.com/b/vcblog/archive/2013/09/11/introducing-gw-compiler-switch.aspx # myenv.Append( CCFLAGS=["/Gw", "/Gy"] ) myenv.Append( LINKFLAGS=["/OPT:REF"]) # http://blogs.msdn.com/b/vcblog/archive/2014/03/25/linker-enhancements-in-visual-studio-2013-update-2-ctp2.aspx # myenv.Append( CCFLAGS=["/Zc:inline"]) # Apply any link time optimization settings as selected by the 'lto' option. if has_option('lto'): if using_msvc(): # Note that this is actually more aggressive than LTO, it is whole program # optimization due to /GL. However, this is historically what we have done for # windows, so we are keeping it. # # /GL implies /LTCG, so no need to say it in CCFLAGS, but we do need /LTCG on the # link flags. myenv.Append(CCFLAGS=['/GL']) myenv.Append(LINKFLAGS=['/LTCG']) myenv.Append(ARFLAGS=['/LTCG']) elif using_gcc() or using_clang(): # For GCC and clang, the flag is -flto, and we need to pass it both on the compile # and link lines. if AddToCCFLAGSIfSupported(myenv, '-flto'): myenv.Append(LINKFLAGS=['-flto']) def LinkHelloWorld(context, adornment = None): test_body = """ #include int main() { std::cout << "Hello, World!" << std::endl; return 0; } """ message = "Trying to link with LTO" if adornment: message = message + " " + adornment message = message + "..." context.Message(message) ret = context.TryLink(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'LinkHelloWorld' : LinkHelloWorld, }) # Some systems (clang, on a system with the BFD linker by default) may need to # explicitly request the gold linker for LTO to work. If we can't LTO link a # simple program, see if -fuse=ld=gold helps. if not conf.LinkHelloWorld(): conf.env.Append(LINKFLAGS=["-fuse-ld=gold"]) if not conf.LinkHelloWorld("(with -fuse-ld=gold)"): myenv.ConfError("Error: Couldn't link with LTO") myenv = conf.Finish() else: myenv.ConfError("Link time optimization requested, " + "but selected compiler does not honor -flto" ) else: myenv.ConfError("Don't know how to enable --lto on current toolchain") # When using msvc, check for support for __declspec(thread), unless we have been asked # explicitly not to use it. For other compilers, see if __thread works. if using_msvc(): haveDeclSpecThread = False if not has_option("disable-declspec-thread"): def CheckDeclspecThread(context): test_body = """ __declspec( thread ) int tsp_int; int main(int argc, char* argv[]) { tsp_int = argc; return 0; } """ context.Message('Checking for __declspec(thread)... ') ret = context.TryLink(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckDeclspecThread' : CheckDeclspecThread, }) haveDeclSpecThread = conf.CheckDeclspecThread() conf.Finish() if haveDeclSpecThread: myenv.Append(CPPDEFINES=['MONGO_HAVE___DECLSPEC_THREAD']) else: def CheckUUThread(context): test_body = """ __thread int tsp_int; int main(int argc, char* argv[]) { tsp_int = argc; return 0; } """ context.Message('Checking for __thread... ') ret = context.TryLink(textwrap.dedent(test_body), ".cpp") context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckUUThread' : CheckUUThread, }) haveUUThread = conf.CheckUUThread() conf.Finish() if haveUUThread: myenv.Append(CPPDEFINES=['MONGO_HAVE___THREAD']) def CheckCXX11Atomics(context): test_body = """ #include int main(int argc, char **argv) { std::atomic a(0); return a.fetch_add(1); } """ context.Message('Checking for C++11 support... ') ret = context.TryLink(textwrap.dedent(test_body), '.cpp') context.Result(ret) return ret; def CheckGCCAtomicBuiltins(context): test_body = """ int main(int argc, char **argv) { int a = 0; int b = 0; int c = 0; __atomic_compare_exchange(&a, &b, &c, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return 0; } """ context.Message('Checking for gcc __atomic builtins... ') ret = context.TryLink(textwrap.dedent(test_body), '.cpp') context.Result(ret) return ret def CheckGCCSyncBuiltins(context): test_body = """ int main(int argc, char **argv) { int a = 0; return __sync_fetch_and_add(&a, 1); } // // Figure out if we are using gcc older than 4.2 to target 32-bit x86. If so, error out // even if we were able to compile the __sync statement, due to // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40693 // #if defined(__i386__) #if !defined(__clang__) #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 2) #error "Refusing to use __sync in 32-bit mode with gcc older than 4.2" #endif #endif #endif """ context.Message('Checking for useable __sync builtins... ') ret = context.TryLink(textwrap.dedent(test_body), '.cpp') context.Result(ret) return ret # not all C++11-enabled gcc versions have type properties def CheckCXX11IsTriviallyCopyable(context): test_body = """ #include int main(int argc, char **argv) { class Trivial { int trivial1; double trivial2; struct { float trivial3; short trivial4; } trivial_member; }; class NotTrivial { int x, y; NotTrivial(const NotTrivial& o) : x(o.y), y(o.x) {} }; static_assert(std::is_trivially_copyable::value, "I should be trivially copyable"); static_assert(!std::is_trivially_copyable::value, "I should not be trivially copyable"); return 0; } """ context.Message('Checking for C++11 is_trivially_copyable support... ') ret = context.TryCompile(textwrap.dedent(test_body), '.cpp') context.Result(ret) return ret conf = Configure(myenv, help=False, custom_tests = { 'CheckCXX11Atomics': CheckCXX11Atomics, 'CheckGCCAtomicBuiltins': CheckGCCAtomicBuiltins, 'CheckGCCSyncBuiltins': CheckGCCSyncBuiltins, 'CheckCXX11IsTriviallyCopyable': CheckCXX11IsTriviallyCopyable, }) # Figure out what atomics mode to use by way of the tests defined above. # # Non_windows: > __atomic > __sync # Windows: > Interlocked functions / intrinsics. # # If we are in C++11 mode, try to use . This is unusual for us, as typically we # only use __cplusplus >= 201103L to decide if we want to enable a feature. We make a # special case for the atomics and use them on platforms that offer them even if they don't # advertise full conformance. For MSVC systems, if we don't have then no more # checks are required. Otherwise, we are on a GCC/clang system, where we may have __atomic # or __sync, so try those in that order next. # # If we don't end up defining a MONGO_HAVE for the atomics, we will end up falling back to # the Microsoft Interlocked functions/intrinsics when using MSVC, or the gcc_intel # implementation of hand-rolled assembly if using gcc/clang. if (using_msvc() or (cxx11_mode == "on")) and conf.CheckCXX11Atomics(): conf.env['MONGO_HAVE_CXX11_ATOMICS'] = True elif using_gcc() or using_clang(): # Prefer the __atomic builtins. If we don't have those, try for __sync. Otherwise # atomic_intrinsics.h will try to fall back to the hand-rolled assembly implementations # in atomic_intrinsics_gcc_intel for x86 platforms. if conf.CheckGCCAtomicBuiltins(): conf.env["MONGO_HAVE_GCC_ATOMIC_BUILTINS"] = True else: if conf.CheckGCCSyncBuiltins(): conf.env["MONGO_HAVE_GCC_SYNC_BUILTINS"] = True if (cxx11_mode == "on") and conf.CheckCXX11IsTriviallyCopyable(): conf.env['MONGO_HAVE_STD_IS_TRIVIALLY_COPYABLE'] = True myenv = conf.Finish() if using_msvc(): # TODO: This is really only needed for MSVC 12, but we have no current way to know # which MSVC version we have. Presuming that this is harmless on other MSVC # implementations. Without this, gtest doesn't build. We need to apply universally, not # just while builing gtest. myenv.Append(CPPDEFINES=[('_VARIADIC_MAX', 10)]) conf = Configure(myenv) conf.env["MONGO_SSL"] = bool(has_option("ssl")) if conf.env["MONGO_SSL"]: sslLibName = "ssl" cryptoLibName = "crypto" if windows: sslLibName = "ssleay32" cryptoLibName = "libeay32" if not conf.CheckLibWithHeader( sslLibName, ["openssl/ssl.h"], "C", "SSL_version(NULL);", autoadd=True): conf.env.ConfError("Couldn't find OpenSSL ssl.h header and library") if not conf.CheckLibWithHeader( cryptoLibName, ["openssl/crypto.h"], "C", "SSLeay_version(0);", autoadd=True): conf.env.ConfError("Couldn't find OpenSSL crypto.h header and library") def CheckLinkSSL(context): test_body = """ #include #include #include int main() { SSL_library_init(); SSL_load_error_strings(); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); ERR_free_strings(); return EXIT_SUCCESS; } """ context.Message("Checking that linking to OpenSSL works...") ret = context.TryLink(textwrap.dedent(test_body), ".c") context.Result(ret) return ret conf.AddTest("CheckLinkSSL", CheckLinkSSL) if not conf.CheckLinkSSL(): conf.env.ConfError("SSL is enabled, but is unavailable") if conf.CheckDeclaration( "FIPS_mode_set", includes=""" #include #include """): conf.env.Append(CPPDEFINES=["MONGO_HAVE_FIPS_MODE_SET"]) if not conf.CheckCXXHeader( "boost/version.hpp" ): conf.env.ConfError("Could not find boost headers in include search path") if (not windows) and boostSuffixList: # We don't do this for windows because we rely on autolib. for b in boostLibs: boostCandidates = ["boost_" + b + suffix for suffix in boostSuffixList] if not conf.CheckLib(boostCandidates, language="C++"): conf.env.ConfError("can't find boost") # We need xtime internally no matter what the local boost thread version may be since we # cannot require the existence of chrono. It is important that no uses of xtime become part # of the public interface of the library so that we do not impose this burden on our # consumers. conf.env.Append(CPPDEFINES=[("BOOST_THREAD_USES_DATETIME")]) if conf.CheckHeader('unistd.h'): conf.env['MONGO_HAVE_HEADER_UNISTD_H'] = True if posix_system: conf.env.Append(CPPDEFINES=['MONGO_HAVE_HEADER_UNISTD_H']) conf.CheckLib('rt') if posix_monotonic_clock: conf.env.Append(CPPDEFINES=['MONGO_HAVE_POSIX_MONOTONIC_CLOCK']) if solaris: conf.CheckLib( "nsl" ) conf.env['MONGO_SASL'] = bool(has_option("use-sasl-client")) if conf.env['MONGO_SASL'] and not conf.env['MONGO_SSL']: myenv.FatalError("SASL support requires --ssl") if conf.env['MONGO_SASL'] and not conf.CheckLibWithHeader( "sasl2", ["stddef.h","sasl/sasl.h"], "C", "sasl_version_info(0, 0, 0, 0, 0, 0);", autoadd=True ): myenv.ConfError("Couldn't find SASL header/libraries") # requires ports devel/libexecinfo to be installed if freebsd or openbsd: if not conf.CheckLib("execinfo"): myenv.ConfError("Cannot find libexecinfo, please install devel/libexecinfo") # check for presence of timegm(3) and polyfill if needed conf.env['MONGO_HAVE_TIMEGM'] = conf.CheckDeclaration( 'timegm', includes="#include ", language='C') if conf.env['MONGO_HAVE_TIMEGM']: conf.env.Append(CPPDEFINES=['MONGO_HAVE_TIMEGM']) # check for presence of strnlen(3) and polyfill if needed if conf.CheckDeclaration('strnlen', includes="#include ", language='C'): conf.env['MONGO_HAVE_STRNLEN'] = True return conf.Finish() env = doConfigure( env ) env['PDB'] = '${TARGET.base}.pdb' # ---- Docs ---- def build_docs(env, target, source): buildscripts.docs.main() env.Alias("docs", [], [build_docs]) env.AlwaysBuild("docs") # --- lint ---- def doLint( env , target , source ): import buildscripts.clang_format if not buildscripts.clang_format.lint(None, []): raise Exception("clang-format lint errors") if not buildscripts.lint.run_lint( [ "src/mongo/" ] ): raise Exception( "lint errors" ) env.Alias( "lint" , [] , [ doLint ] ) env.AlwaysBuild( "lint" ) # --- an uninstall target --- if len(COMMAND_LINE_TARGETS) > 0 and 'uninstall' in COMMAND_LINE_TARGETS: SetOption("clean", 1) # By inspection, changing COMMAND_LINE_TARGETS here doesn't do # what we want, but changing BUILD_TARGETS does. BUILD_TARGETS.remove("uninstall") BUILD_TARGETS.append("install") # The following symbols are exported for use in subordinate SConscript files. # Ideally, the SConscript files would be purely declarative. They would only # import build environment objects, and would contain few or no conditional # statements or branches. # # Currently, however, the SConscript files do need some predicates for # conditional decision making that hasn't been moved up to this SConstruct file, # and they are exported here, as well. Export("env") Export("get_option") Export("has_option") Export("darwin windows solaris linux freebsd nix") Export("debugBuild optBuild") Export("use_clang") env.SConscript('src/SConscript', variant_dir='$VARIANT_DIR', duplicate=False) # --- Coverage --- if has_option("gcov"): env['GCOV_BASE_DIR'] = env.Dir(".").abspath env['GCOV_BUILD_DIR'] = env.Dir("$VARIANT_DIR").abspath # Zero out all the counters -- depends on tests being built env.Alias( 'zero_counters', ['unittests', 'clientTests', 'integration_tests'], ['lcov -z -b $GCOV_BASE_DIR -d $GCOV_BUILD_DIR'] ) env.AlwaysBuild('zero_counters') # Generates test coverage information -- depends on tests being run env.Command( target='$VARIANT_DIR/coverage.info', source=['zero_counters', 'test', 'smokeClient', 'integration'], action='lcov --no-external -c -b $GCOV_BASE_DIR -d $GCOV_BUILD_DIR -o $TARGET' ) env.AlwaysBuild('coverage.info') # Strip third_party and build related coverage info stripCmd = env.Command( target=None, source='$VARIANT_DIR/coverage.info', action=[ 'lcov -r $SOURCE src/third_party/\* -o $SOURCE', 'lcov -r $SOURCE build/\* -o $SOURCE', 'lcov -r $SOURCE \*_test.cpp -o $SOURCE', 'lcov -r $SOURCE src/mongo/client/examples/\* -o $SOURCE', 'lcov -r $SOURCE src/mongo/dbtests/\* -o $SOURCE', 'lcov -r $SOURCE src/mongo/unittest/\* -o $SOURCE', 'lcov -r $SOURCE src/mongo/bson/bsondemo/\* -o $SOURCE', ], ) env.AlwaysBuild(stripCmd) env.Alias('strip_coverage', stripCmd) # Generates the HTML output in "coverage" directory coverageCmd = env.Command( env.Dir('$BUILD_DIR/coverage'), 'strip_coverage', [ 'rm -rf $BUILD_DIR/coverage', 'genhtml --frames --legend -t "MongoDB C++ Driver Coverage" -o $TARGET $VARIANT_DIR/coverage.info' ] ) env.AlwaysBuild(coverageCmd) env.Alias('coverage', coverageCmd) env.Alias('all', ['driver', 'build-unit', 'build-integration', 'build-examples']) env.Alias('test', ['unit', 'integration', 'examples']) Default('driver') mongo-cxx-driver-legacy-1.1.2/THIRD-PARTY-NOTICES000066400000000000000000000241001273231111400207510ustar00rootroot00000000000000MongoDB uses third-party libraries or other resources that may be distributed under licenses different than the MongoDB software. In the event that we accidentally failed to list a required notice, please bring it to our attention through any of the ways detailed here: https://jira.mongodb.org/browse/CXX The attached notices are provided for information only. For any licenses that require disclosure of source, sources are available at https://github.com/mongodb/mongo-cxx-driver. 1) License Notice for The Loki Library -------------------------------------- Copyright (c) 2000 Andrei Alexandrescu Copyright (c) 2000 Petru Marginean Copyright (c) 2005 Joshua Lehrer Permission to use, copy, modify, distribute and sell this software for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The author makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. 2) License Notice for MurmurHash -------------------------------- Copyright (c) 2010-2012 Austin Appleby 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. 3) License Notice for The Google C++ Testing Framework (Google Test) -------------------------------------------------------------------- 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. 4) License Notice for JsonCpp ----------------------------- The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... The author (Baptiste Lepilleur) explicitly disclaims copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License The full text of the MIT License follows: ======================================================================== Copyright (c) 2007-2010 Baptiste Lepilleur 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. ======================================================================== (END LICENSE TEXT) The MIT license is compatible with both the GPL and commercial software, affording one all of the rights of Public Domain with the minor nuisance of being required to keep the above copyright notice and license text in the source code. Note also that by accepting the Public Domain "license" you can re-license your copy using whatever license you like. 5) License Notice for RestClient -------------------------------- Copyright (c) 2010 Daniel Schauenberg 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. 6) License Notice for the TZ Database ------------------------------------- The tzcode library is published as part of the TZ Database by IANA at https://www.iana.org/time-zones Ownership is described in https://www.rfc-editor.org/bcp/bcp175.txt: The TZ database itself is not an IETF Contribution or an IETF document. Rather it is a pre-existing and regularly updated work that is in the public domain, and is intended to remain in the public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do not apply to the TZ Database or contributions that individuals make to it. Should any claims be made and substantiated against the TZ Database, the organization that is providing the IANA Considerations defined in this RFC, under the memorandum of understanding with the IETF, currently ICANN, may act in accordance with all competent court orders. No ownership claims will be made by ICANN or the IETF Trust on the database or the code. Any person making a contribution to the database or code waives all rights to future claims in that contribution or in the TZ Database. 7) License Notice for Independent implementation of MD5 by Aladdin Enterprises ------------------------------------------------------------------------------ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com NOTE: Per restriction 2 above, this file has been altered by MongoDB as follows: 1. The functions md5_init, md5_append, and md5_finish have been moved into the 'mongo' namespace and given C++ linkage, so that static archives of this library may be combined with other libraries that expose functions of the same name. mongo-cxx-driver-legacy-1.1.2/docs/000077500000000000000000000000001273231111400171105ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/docs/.gitkeep000066400000000000000000000000001273231111400205270ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/etc/000077500000000000000000000000001273231111400167335ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/etc/asan.blacklist000066400000000000000000000000001273231111400215350ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/etc/doxygen/000077500000000000000000000000001273231111400204105ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/etc/doxygen/config000066400000000000000000000253151273231111400216060ustar00rootroot00000000000000#--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "MongoDB C++ Driver" PROJECT_NUMBER = legacy-1.1.2 OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = src/mongo INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.vhd \ *.vhdl RECURSIVE = YES EXCLUDE = src/mongo/bson/bsondemo \ src/mongo/client/examples \ src/mongo/client/private \ src/mongo/dbtests \ src/mongo/integration \ src/mongo/orchestration \ src/mongo/unittest EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NONE TREEVIEW_WIDTH = 250 FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_FONTNAME = DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Options related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = YES mongo-cxx-driver-legacy-1.1.2/etc/lsan.suppressions000066400000000000000000000000001273231111400223550ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/etc/pick_from_log.pl000077500000000000000000000142271273231111400221130ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; use Term::ANSIColor; use Term::ReadKey; use List::Util qw( min max ); use Getopt::Long; my $cxx; my $mongo; GetOptions( 'cxx=s' => \$cxx, 'mongo=s' => \$mongo, 'help' => sub { HELP(0); }, ) or HELP(1); $cxx or print "Please enter a path to the mongodb cxx driver repository\n" and HELP(1); $mongo or print "Please enter a path to the mongodb mongo repository\n" and HELP(1); my @kept; my $sha; my @lines; my $has_file = 0; my @decisions; open FILE, "cd $mongo; git log --stat --oneline --reverse @ARGV |" or die "Couldn't execute git log: $!"; my $total_shas = 0; while (my $line = ) { if ($line =~ /^\s/) { if ($line =~ /^ \d+ files? changed/) { push @lines, $line; } else { my ($path) = ($line =~ /^ (\S+)\s*\|/); if (! $path) { die $line; } if (-f "$cxx/$path") { $has_file = 1; push @lines, color('bold green') . $line . color('reset'); } else { push @lines, color('bold red') . $line . color('reset'); } } } else { if ($has_file) { $total_shas++; $has_file = 0; push @decisions, [$sha, [@lines]]; } @lines = (); ($sha) = ($line =~ /^(\S+)/); push @lines, color('bold yellow') . $line . color('reset'); } } close FILE; if ($has_file) { $total_shas++; $has_file = 0; push @decisions, [$sha, [@lines]]; } @kept = map { "" } @decisions; ReadMode 4; my $seen_shas; for (my $i = 0; $i < scalar(@decisions); $i++) { $seen_shas = $i + 1; eval { if (! decision($i, @{$decisions[$i]})) { $i = max(-1, $i - 2); } }; if ($@) { ReadMode 0; die $@; } } ReadMode 0; print join('', map { "$_\n" } @kept); exit 0; sub debug { warn @_; sleep 1; } sub decision { my ($index, $sha, $lines) = @_; my $offset = 0; my $y = $kept[$index] ? color('bold green') . 'Y' . color('reset') : 'y'; my $n = $kept[$index] ? 'n' : color('bold red') . 'N' . color('reset'); my $options = < sub { $kept[$index] = $sha; return 1; }, 'n' => sub { $kept[$index] = ""; return 1; }, 'b' => sub { return 2; }, 's' => sub { system("cd $mongo; git show $sha"); return 0; }, 'q' => sub { ReadMode 0; exit 0; }, chr(10) => sub { return 1; }, chr(32) => sub { return 1; }, chr(27) => sub { my $key = ord(ReadKey(0)); if ($key == 91) { $key = ord(ReadKey(0)); if ($key == 65) { $offset--; } elsif ($key == 66) { $offset++; } elsif ($key == 49) { $key = ord(ReadKey(0)); if ($key == 126) { $offset = 0; } else { debug "pressed 27.91.49." . $key . "\n"; } } elsif ($key == 52) { $key = ord(ReadKey(0)); if ($key == 126) { $offset = scalar(@$lines); } else { debug "pressed 27.91.52." . $key . "\n"; } } elsif ($key == 53) { $key = ord(ReadKey(0)); if ($key == 126) { $offset = max(0, $offset - 10); } else { debug "pressed 27.91.53." . $key . "\n"; } } elsif ($key == 54) { $key = ord(ReadKey(0)); if ($key == 126) { $offset = min(scalar(@$lines), $offset + 10); } else { debug "pressed 27.91.54." . $key . "\n"; } } else { debug "pressed 27.91." . $key . "\n"; } } else { debug "pressed 27." . $key . "\n"; } return 0; }, ); if ($table{$key}) { my $x = $table{$key}->(); if ($x == 1) { last; } elsif ($x == 2) { return 0; } } else { debug "pressed " . ord($key) . "\n"; } display($lines, \$offset, $options); } return 1; } sub display { my ($lines, $offset, $options) = @_; print `clear`; my ($width, $height) = GetTerminalSize(); my $window = $height - (scalar(split /\n/, $options) + 10); $$offset = max($$offset, 0); $$offset = min($$offset, max(scalar(@$lines) - $window - 1, 0)); my $min = $$offset; my $max = min($window + $$offset, scalar(@$lines)-1); printf("%d% (%d/%d)\n", (100 * $seen_shas / $total_shas), $seen_shas, $total_shas); print map { if (length($_) <= $width) { $_; } else { substr($_, 0, $width - 3) . "...\n"; } } @$lines[$min..$max]; print "\n", $options; } sub HELP { my ($exit) = @_; my $usage = <>> check_output(["ls", "-l", "/dev/null"]) 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' The stdout argument is not allowed as it is used internally. To capture standard error in the result, use stderr=STDOUT. >>> check_output(["/bin/sh", "-c", ... "ls -l non_existent_file ; exit 0"], ... stderr=STDOUT) 'ls: non_existent_file: No such file or directory\n' """ if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) output, unused_err = process.communicate() retcode = process.poll() if retcode: cmd = kwargs.get("args") if cmd is None: cmd = popenargs[0] raise CalledProcessError(retcode, cmd, output) return output def callo(args): """Call a program, and capture its output """ return check_output(args) def get_llvm_url(version, llvm_distro): """Get the url to download clang-format from llvm.org """ return CLANG_FORMAT_SOURCE_URL_BASE.substitute( version=version, llvm_distro=llvm_distro) def get_tar_path(version, tar_path): """ Get the path to clang-format in the llvm tarball """ return CLANG_FORMAT_SOURCE_TAR_BASE.substitute( version=version, tar_path=tar_path) def extract_clang_format(tar_path): # Extract just the clang-format binary # On OSX, we shell out to tar because tarfile doesn't support xz compression if sys.platform == 'darwin': subprocess.call(['tar', '-xzf', tar_path, '*clang-format*']) # Otherwise we use tarfile because some versions of tar don't support wildcards without # a special flag else: tarfp = tarfile.open(tar_path) for name in tarfp.getnames(): if name.endswith('clang-format'): tarfp.extract(name) tarfp.close() def get_clang_format_from_llvm(llvm_distro, tar_path, dest_file): """Download clang-format from llvm.org, unpack the tarball, and put clang-format in the specified place """ # Build URL url = get_llvm_url(CLANG_FORMAT_VERSION, llvm_distro) dest_dir = tempfile.gettempdir() temp_tar_file = os.path.join(dest_dir, "temp.tar.xz") # Download from LLVM print("Downloading clang-format %s from %s, saving to %s" % (CLANG_FORMAT_VERSION, url, temp_tar_file)) urllib.urlretrieve(url, temp_tar_file) extract_clang_format(temp_tar_file) # Destination Path shutil.move(get_tar_path(CLANG_FORMAT_VERSION, tar_path), dest_file) def get_clang_format_from_linux_cache(dest_file): """Get clang-format from mongodb's cache """ # Get URL url = CLANG_FORMAT_HTTP_LINUX_CACHE dest_dir = tempfile.gettempdir() temp_tar_file = os.path.join(dest_dir, "temp.tar.xz") # Download the file print("Downloading clang-format %s from %s, saving to %s" % (CLANG_FORMAT_VERSION, url, temp_tar_file)) urllib.urlretrieve(url, temp_tar_file) extract_clang_format(temp_tar_file) # Destination Path shutil.move("llvm/Release/bin/clang-format", dest_file) class ClangFormat(object): """Class encapsulates finding a suitable copy of clang-format, and linting/formating an individual file """ def __init__(self, path, cache_dir): if os.path.exists('/usr/bin/clang-format-3.6'): clang_format_progname = 'clang-format-3.6' else: clang_format_progname = CLANG_FORMAT_PROGNAME # Initialize clang-format configuration information if sys.platform.startswith("linux"): #"3.6.0/clang+llvm-3.6.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz self.platform = "linux_x64" self.llvm_distro = "x86_64-linux-gnu-ubuntu" self.tar_path = "x86_64-linux-gnu" elif sys.platform == "win32": self.platform = "windows_x64" self.llvm_distro = "windows_x64" self.tar_path = None clang_format_progname += ".exe" elif sys.platform == "darwin": #"3.6.0/clang+llvm-3.6.0-x86_64-apple-darwin.tar.xz self.platform = "darwin_x64" self.llvm_distro = "x86_64-apple-darwin" self.tar_path = "x86_64-apple-darwin" self.path = None # Find Clang-Format now if path is not None: if os.path.isfile(path): self.path = path else: print("WARNING: Could not find clang-format %s" % (path)) # Check the envionrment variable if "MONGO_CLANG_FORMAT" in os.environ: self.path = os.environ["MONGO_CLANG_FORMAT"] if self.path and not self._validate_version(warn=True): self.path = None # Check the users' PATH environment variable now if self.path is None: self.path = spawn.find_executable(clang_format_progname) if self.path and not self._validate_version(warn=True): self.path = None # If Windows, try to grab it from Program Files if sys.platform == "win32": win32bin = os.path.join(os.environ["ProgramFiles(x86)"], "LLVM\\bin\\clang-format.exe") if os.path.exists(win32bin): self.path = win32bin # Have not found it yet, download it from the web if self.path is None: if not os.path.isdir(cache_dir): os.makedirs(cache_dir) self.path = os.path.join(cache_dir, clang_format_progname) if not os.path.isfile(self.path): if sys.platform.startswith("linux"): get_clang_format_from_linux_cache(self.path) elif sys.platform == "darwin": get_clang_format_from_llvm(self.llvm_distro, self.tar_path, self.path) else: print("ERROR: clang-format.py does not support downloading clang-format " + " on this platform, please install clang-format " + CLANG_FORMAT_VERSION) # Validate we have the correct version self._validate_version() self.print_lock = threading.Lock() def _validate_version(self, warn=False): """Validate clang-format is the expected version """ try: cf_version = callo([self.path, "--version"]) except CalledProcessError: cf_version = "clang-format call failed." if CLANG_FORMAT_VERSION in cf_version: return True if warn: print("WARNING: clang-format found in path, but incorrect version found at " + self.path + " with version: " + cf_version) return False def lint(self, file_name): """Check the specified file has the correct format """ with open(file_name, 'r') as original_text: original_file = original_text.read() # Get formatted file as clang-format would format the file formatted_file = callo([self.path, "--style=file", file_name]) if original_file != formatted_file: original_lines = original_file.splitlines() formatted_lines = formatted_file.splitlines() result = difflib.unified_diff(original_lines, formatted_lines) # Take a lock to ensure diffs do not get mixed with self.print_lock: print("ERROR: Found diff for " + file_name) print("To fix formatting errors, run %s --style=file -i %s" % (self.path, file_name)) for line in result: print(line.rstrip()) return False return True def format(self, file_name): """Update the format of the specified file """ # Update the file with clang-format return not subprocess.call([self.path, "--style=file", "-i", file_name]) def parallel_process(items, func): """Run a set of work items to completion """ try: cpus = cpu_count() except NotImplementedError: cpus = 1 # print("Running across %d cpus" % (cpus)) task_queue = Queue.Queue() # Use a list so that worker function will capture this variable pp_event = threading.Event() pp_result = [True] pp_lock = threading.Lock() def worker(): """Worker thread to process work items in parallel """ while not pp_event.is_set(): try: item = task_queue.get_nowait() except Queue.Empty: # if the queue is empty, exit the worker thread pp_event.set() return try: ret = func(item) finally: # Tell the queue we finished with the item task_queue.task_done() # Return early if we fail, and signal we are done if not ret: with pp_lock: pp_result[0] = False pp_event.set() return # Enqueue all the work we want to process for item in items: task_queue.put(item) # Process all the work threads = [] for cpu in range(cpus): thread = threading.Thread(target=worker) thread.daemon = True thread.start() threads.append(thread) # Wait for the threads to finish # Loop with a timeout so that we can process Ctrl-C interrupts # Note: On Python 2.6 wait always returns None so we check is_set also, # This works because we only set the event once, and never reset it while not pp_event.wait(1) and not pp_event.is_set(): time.sleep(1) for thread in threads: thread.join() return pp_result[0] def get_base_dir(): """Get the base directory for mongo repo. This script assumes that it is running in site_scons/buildscripts/, and uses that to find the base directory. """ try: return subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).rstrip() except: # We are not in a valid git directory. Use the script path instead. return os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) def get_repos(): """Get a list of Repos to check clang-format for """ base_dir = get_base_dir() paths = [base_dir] return [Repo(p) for p in paths] class Repo(object): """Class encapsulates all knowledge about a git repository, and its metadata to run clang-format. """ def __init__(self, path): self.path = path # Get candidate files self.candidate_files = self._get_candidate_files() self.root = self._get_root() def _callgito(self, args): """Call git for this repository """ # These two flags are the equivalent of -C in newer versions of Git # but we use these to support versions back to ~1.8 return callo(['git', '--git-dir', os.path.join(self.path, ".git"), '--work-tree', self.path] + args) def _get_local_dir(self, path): """Get a directory path relative to the git root directory """ if os.path.isabs(path): return os.path.relpath(path, self.root) return path def get_candidates(self, candidates): """Get the set of candidate files to check by doing an intersection between the input list, and the list of candidates in the repository Returns the full path to the file for clang-format to consume. """ # NOTE: Files may have an absolute root (i.e. leading /) if candidates is not None and len(candidates) > 0: candidates = [self._get_local_dir(f) for f in candidates] valid_files = list(set(candidates).intersection(self.get_candidate_files())) else: valid_files = list(self.get_candidate_files()) # Get the full file name here valid_files = [os.path.normpath(os.path.join(self.root, f)) for f in valid_files] return valid_files def get_root(self): """Get the root directory for this repository """ return self.root def _get_root(self): """Gets the root directory for this repository from git """ gito = self._callgito(['rev-parse', '--show-toplevel']) return gito.rstrip() def get_candidate_files(self): """Get a list of candidate files """ return self._get_candidate_files() def _get_candidate_files(self): """Query git to get a list of all files in the repo to consider for analysis """ gito = self._callgito(["ls-files"]) # This allows us to pick all the interesting files # in the mongo and mongo-enterprise repos file_list = [line.rstrip() for line in gito.splitlines() if "src" in line and not "src/third_party" in line] files_match = re.compile('\\.(h|cpp)$') file_list = [a for a in file_list if files_match.search(a)] return file_list def expand_file_string(glob_pattern): """Expand a string that represents a set of files """ return [os.path.abspath(f) for f in globstar.iglob(glob_pattern)] def get_files_to_check(files): """Filter the specified list of files to check down to the actual list of files that need to be checked.""" candidates = [] # Get a list of candidate_files candidates = [expand_file_string(f) for f in files] candidates = list(itertools.chain.from_iterable(candidates)) repos = get_repos() valid_files = list(itertools.chain.from_iterable([r.get_candidates(candidates) for r in repos])) return valid_files def get_files_to_check_from_patch(patches): """Take a patch file generated by git diff, and scan the patch for a list of files to check. """ candidates = [] # Get a list of candidate_files check = re.compile(r"^diff --git a\/([a-z\/\.\-_0-9]+) b\/[a-z\/\.\-_0-9]+") lines = [] for patch in patches: with open(patch, "rb") as infile: lines += infile.readlines() candidates = [check.match(line).group(1) for line in lines if check.match(line)] repos = get_repos() valid_files = list(itertools.chain.from_iterable([r.get_candidates(candidates) for r in repos])) return valid_files def _get_build_dir(): """Get the location of the scons' build directory in case we need to download clang-format """ return os.path.join(get_base_dir(), "build") def _lint_files(clang_format, files): """Lint a list of files with clang-format """ clang_format = ClangFormat(clang_format, _get_build_dir()) lint_clean = parallel_process([os.path.abspath(f) for f in files], clang_format.lint) if not lint_clean: print("ERROR: Code Style does not match coding style") sys.exit(1) def lint_patch(clang_format, infile): """Lint patch command entry point """ files = get_files_to_check_from_patch(infile) # Patch may have files that we do not want to check which is fine if files: _lint_files(clang_format, files) def lint(clang_format, glob): """Lint files command entry point """ files = get_files_to_check(glob) _lint_files(clang_format, files) return True def _format_files(clang_format, files): """Format a list of files with clang-format """ clang_format = ClangFormat(clang_format, _get_build_dir()) format_clean = parallel_process([os.path.abspath(f) for f in files], clang_format.format) if not format_clean: print("ERROR: failed to format files") sys.exit(1) def format_func(clang_format, glob): """Format files command entry point """ files = get_files_to_check(glob) _format_files(clang_format, files) def usage(): """Print usage """ print("clang-format.py supports 3 commands [ lint, lint-patch, format ]. Run " " -? for more information") def main(): """Main entry point """ if len(sys.argv) > 1: command = sys.argv[1] parser = OptionParser() parser.add_option("-c", "--clang-format", type="string", dest="clang_format") if command == "lint": (options, args) = parser.parse_args(args=sys.argv[2:]) lint(options.clang_format, args) elif command == "lint-patch": (options, args) = parser.parse_args(args=sys.argv[2:]) lint_patch(options.clang_format, args) elif command == "format": (options, args) = parser.parse_args(args=sys.argv[2:]) format_func(options.clang_format, args) else: usage() else: usage() if __name__ == "__main__": main() mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/cpplint.py000066400000000000000000004053651273231111400251000ustar00rootroot00000000000000#!/usr/bin/python # # Copyright (c) 2009 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Here are some issues that I've had people identify in my code during reviews, # that I think are possible to flag automatically in a lint tool. If these were # caught by lint, it would save time both for myself and that of my reviewers. # Most likely, some of these are beyond the scope of the current lint framework, # but I think it is valuable to retain these wish-list items even if they cannot # be immediately implemented. # # Suggestions # ----------- # - Check for no 'explicit' for multi-arg ctor # - Check for boolean assign RHS in parens # - Check for ctor initializer-list colon position and spacing # - Check that if there's a ctor, there should be a dtor # - Check accessors that return non-pointer member variables are # declared const # - Check accessors that return non-const pointer member vars are # *not* declared const # - Check for using public includes for testing # - Check for spaces between brackets in one-line inline method # - Check for no assert() # - Check for spaces surrounding operators # - Check for 0 in pointer context (should be NULL) # - Check for 0 in char context (should be '\0') # - Check for camel-case method name conventions for methods # that are not simple inline getters and setters # - Check that base classes have virtual destructors # put " // namespace" after } that closes a namespace, with # namespace's name after 'namespace' if it is named. # - Do not indent namespace contents # - Avoid inlining non-trivial constructors in header files # include base/basictypes.h if DISALLOW_EVIL_CONSTRUCTORS is used # - Check for old-school (void) cast for call-sites of functions # ignored return value # - Check gUnit usage of anonymous namespace # - Check for class declaration order (typedefs, consts, enums, # ctor(s?), dtor, friend declarations, methods, member vars) # """Does google-lint on c++ files. The goal of this script is to identify places in the code that *may* be in non-compliance with google style. It does not attempt to fix up these problems -- the point is to educate. It does also not attempt to find all problems, or to ensure that everything it does find is legitimately a problem. In particular, we can get very confused by /* and // inside strings! We do a small hack, which is to ignore //'s with "'s after them on the same line, but it is far from perfect (in either direction). """ import codecs import getopt import math # for log import os import re import sre_compile import string import sys import unicodedata _USAGE = """ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] [--counting=total|toplevel|detailed] [file] ... The style guidelines this tries to follow are those in http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml Every problem is given a confidence score from 1-5, with 5 meaning we are certain of the problem, and 1 meaning it could be a legitimate construct. This will miss some errors, and is not a substitute for a code review. To suppress false-positive errors of a certain category, add a 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) suppresses errors of all categories on that line. The files passed in will be linted; at least one file must be provided. Linted extensions are .cc, .cpp, and .h. Other file types will be ignored. Flags: output=vs7 By default, the output is formatted to ease emacs parsing. Visual Studio compatible output (vs7) may also be used. Other formats are unsupported. verbose=# Specify a number 0-5 to restrict errors to certain verbosity levels. filter=-x,+y,... Specify a comma-separated list of category-filters to apply: only error messages whose category names pass the filters will be printed. (Category names are printed with the message and look like "[whitespace/indent]".) Filters are evaluated left to right. "-FOO" and "FOO" means "do not print categories that start with FOO". "+FOO" means "do print categories that start with FOO". Examples: --filter=-whitespace,+whitespace/braces --filter=whitespace,runtime/printf,+runtime/printf_format --filter=-,+build/include_what_you_use To see a list of all the categories used in cpplint, pass no arg: --filter= counting=total|toplevel|detailed The total number of errors found is always printed. If 'toplevel' is provided, then the count of errors in each of the top-level categories like 'build' and 'whitespace' will also be printed. If 'detailed' is provided, then a count is provided for each category like 'build/class'. """ # We categorize each error message we print. Here are the categories. # We want an explicit list so we can list them all in cpplint --filter=. # If you add a new error message with a new category, add it to the list # here! cpplint_unittest.py should tell you if you forget to do this. # \ used for clearer layout -- pylint: disable-msg=C6013 _ERROR_CATEGORIES = [ 'build/class', 'build/deprecated', 'build/endif_comment', 'build/explicit_make_pair', 'build/forward_decl', 'build/header_guard', 'build/include', 'build/include_alpha', 'build/include_order', 'build/include_what_you_use', 'build/namespaces', 'build/printf_format', 'build/storage_class', 'legal/copyright', 'readability/braces', 'readability/casting', 'readability/check', 'readability/constructors', 'readability/fn_size', 'readability/function', 'readability/multiline_comment', 'readability/multiline_string', 'readability/nolint', 'readability/streams', 'readability/todo', 'readability/utf8', 'runtime/arrays', 'runtime/casting', 'runtime/explicit', 'runtime/int', 'runtime/init', 'runtime/invalid_increment', 'runtime/member_string_references', 'runtime/memset', 'runtime/operator', 'runtime/printf', 'runtime/printf_format', 'runtime/references', 'runtime/rtti', 'runtime/sizeof', 'runtime/string', 'runtime/threadsafe_fn', 'runtime/virtual', 'whitespace/blank_line', 'whitespace/braces', 'whitespace/comma', 'whitespace/comments', 'whitespace/end_of_line', 'whitespace/ending_newline', 'whitespace/indent', 'whitespace/labels', 'whitespace/line_length', 'whitespace/newline', 'whitespace/operators', 'whitespace/parens', 'whitespace/semicolon', 'whitespace/tab', 'whitespace/todo' ] # The default state of the category filter. This is overrided by the --filter= # flag. By default all errors are on, so only add here categories that should be # off by default (i.e., categories that must be enabled by the --filter= flags). # All entries here should start with a '-' or '+', as in the --filter= flag. _DEFAULT_FILTERS = ['-build/include_alpha'] # We used to check for high-bit characters, but after much discussion we # decided those were OK, as long as they were in UTF-8 and didn't represent # hard-coded international strings, which belong in a separate i18n file. # Headers that we consider STL headers. _STL_HEADERS = frozenset([ 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new', 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', 'stl_alloc.h', 'stl_relops.h', 'type_traits.h', 'utility', 'vector', 'vector.h', ]) # Non-STL C++ system headers. _CPP_HEADERS = frozenset([ 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype', 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath', 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef', 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype', 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream', 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip', 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream', 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h', 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h', 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h', 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept', 'stdiostream.h', 'streambuf.h', 'stream.h', 'strfile.h', 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 'valarray', ]) # Assertion macros. These are defined in base/logging.h and # testing/base/gunit.h. Note that the _M versions need to come first # for substring matching to work. _CHECK_MACROS = [ 'DCHECK', 'CHECK', 'EXPECT_TRUE_M', 'EXPECT_TRUE', 'ASSERT_TRUE_M', 'ASSERT_TRUE', 'EXPECT_FALSE_M', 'EXPECT_FALSE', 'ASSERT_FALSE_M', 'ASSERT_FALSE', ] # Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE _CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ('>=', 'GE'), ('>', 'GT'), ('<=', 'LE'), ('<', 'LT')]: _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), ('>=', 'LT'), ('>', 'LE'), ('<=', 'GT'), ('<', 'GE')]: _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement # These constants define types of headers for use with # _IncludeState.CheckNextIncludeOrder(). _C_SYS_HEADER = 1 _CPP_SYS_HEADER = 2 _LIKELY_MY_HEADER = 3 _POSSIBLE_MY_HEADER = 4 _OTHER_HEADER = 5 _regexp_compile_cache = {} # Finds occurrences of NOLINT or NOLINT(...). _RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?') # {str, set(int)}: a map from error categories to sets of linenumbers # on which those errors are expected and should be suppressed. _error_suppressions = {} def ParseNolintSuppressions(filename, raw_line, linenum, error): """Updates the global list of error-suppressions. Parses any NOLINT comments on the current line, updating the global error_suppressions store. Reports an error if the NOLINT comment was malformed. Args: filename: str, the name of the input file. raw_line: str, the line of input text, with comments. linenum: int, the number of the current line. error: function, an error handler. """ # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*). matched = _RE_SUPPRESSION.search(raw_line) if matched: category = matched.group(1) if category in (None, '(*)'): # => "suppress all" _error_suppressions.setdefault(None, set()).add(linenum) else: if category.startswith('(') and category.endswith(')'): category = category[1:-1] if category in _ERROR_CATEGORIES: _error_suppressions.setdefault(category, set()).add(linenum) else: error(filename, linenum, 'readability/nolint', 5, 'Unknown NOLINT error category: %s' % category) def ResetNolintSuppressions(): "Resets the set of NOLINT suppressions to empty." _error_suppressions.clear() def IsErrorSuppressedByNolint(category, linenum): """Returns true if the specified error category is suppressed on this line. Consults the global error_suppressions map populated by ParseNolintSuppressions/ResetNolintSuppressions. Args: category: str, the category of the error. linenum: int, the current line number. Returns: bool, True iff the error should be suppressed due to a NOLINT comment. """ return (linenum in _error_suppressions.get(category, set()) or linenum in _error_suppressions.get(None, set())) def Match(pattern, s): """Matches the string with the pattern, caching the compiled regexp.""" # The regexp compilation caching is inlined in both Match and Search for # performance reasons; factoring it out into a separate function turns out # to be noticeably expensive. if not pattern in _regexp_compile_cache: _regexp_compile_cache[pattern] = sre_compile.compile(pattern) return _regexp_compile_cache[pattern].match(s) def Search(pattern, s): """Searches the string for the pattern, caching the compiled regexp.""" if not pattern in _regexp_compile_cache: _regexp_compile_cache[pattern] = sre_compile.compile(pattern) return _regexp_compile_cache[pattern].search(s) class _IncludeState(dict): """Tracks line numbers for includes, and the order in which includes appear. As a dict, an _IncludeState object serves as a mapping between include filename and line number on which that file was included. Call CheckNextIncludeOrder() once for each header in the file, passing in the type constants defined above. Calls in an illegal order will raise an _IncludeError with an appropriate error message. """ # self._section will move monotonically through this set. If it ever # needs to move backwards, CheckNextIncludeOrder will raise an error. _INITIAL_SECTION = 0 _MY_H_SECTION = 1 _C_SECTION = 2 _CPP_SECTION = 3 _OTHER_H_SECTION = 4 _TYPE_NAMES = { _C_SYS_HEADER: 'C system header', _CPP_SYS_HEADER: 'C++ system header', _LIKELY_MY_HEADER: 'header this file implements', _POSSIBLE_MY_HEADER: 'header this file may implement', _OTHER_HEADER: 'other header', } _SECTION_NAMES = { _INITIAL_SECTION: "... nothing. (This can't be an error.)", _MY_H_SECTION: 'a header this file implements', _C_SECTION: 'C system header', _CPP_SECTION: 'C++ system header', _OTHER_H_SECTION: 'other header', } def __init__(self): dict.__init__(self) # The name of the current section. self._section = self._INITIAL_SECTION # The path of last found header. self._last_header = '' def CanonicalizeAlphabeticalOrder(self, header_path): """Returns a path canonicalized for alphabetical comparison. - replaces "-" with "_" so they both cmp the same. - removes '-inl' since we don't require them to be after the main header. - lowercase everything, just in case. Args: header_path: Path to be canonicalized. Returns: Canonicalized path. """ return header_path.replace('-inl.h', '.h').replace('-', '_').lower() def IsInAlphabeticalOrder(self, header_path): """Check if a header is in alphabetical order with the previous header. Args: header_path: Header to be checked. Returns: Returns true if the header is in alphabetical order. """ canonical_header = self.CanonicalizeAlphabeticalOrder(header_path) if self._last_header > canonical_header: return False self._last_header = canonical_header return True def CheckNextIncludeOrder(self, header_type): """Returns a non-empty error message if the next header is out of order. This function also updates the internal state to be ready to check the next include. Args: header_type: One of the _XXX_HEADER constants defined above. Returns: The empty string if the header is in the right order, or an error message describing what's wrong. """ error_message = ('Found %s after %s' % (self._TYPE_NAMES[header_type], self._SECTION_NAMES[self._section])) last_section = self._section if header_type == _C_SYS_HEADER: if self._section <= self._C_SECTION: self._section = self._C_SECTION else: self._last_header = '' return error_message elif header_type == _CPP_SYS_HEADER: if self._section <= self._CPP_SECTION: self._section = self._CPP_SECTION else: self._last_header = '' return error_message elif header_type == _LIKELY_MY_HEADER: if self._section <= self._MY_H_SECTION: self._section = self._MY_H_SECTION else: self._section = self._OTHER_H_SECTION elif header_type == _POSSIBLE_MY_HEADER: if self._section <= self._MY_H_SECTION: self._section = self._MY_H_SECTION else: # This will always be the fallback because we're not sure # enough that the header is associated with this file. self._section = self._OTHER_H_SECTION else: assert header_type == _OTHER_HEADER self._section = self._OTHER_H_SECTION if last_section != self._section: self._last_header = '' return '' class _CppLintState(object): """Maintains module-wide state..""" def __init__(self): self.verbose_level = 1 # global setting. self.error_count = 0 # global count of reported errors # filters to apply when emitting error messages self.filters = _DEFAULT_FILTERS[:] self.counting = 'total' # In what way are we counting errors? self.errors_by_category = {} # string to int dict storing error counts # output format: # "emacs" - format that emacs can parse (default) # "vs7" - format that Microsoft Visual Studio 7 can parse self.output_format = 'emacs' def SetOutputFormat(self, output_format): """Sets the output format for errors.""" self.output_format = output_format def SetVerboseLevel(self, level): """Sets the module's verbosity, and returns the previous setting.""" last_verbose_level = self.verbose_level self.verbose_level = level return last_verbose_level def SetCountingStyle(self, counting_style): """Sets the module's counting options.""" self.counting = counting_style def SetFilters(self, filters): """Sets the error-message filters. These filters are applied when deciding whether to emit a given error message. Args: filters: A string of comma-separated filters (eg "+whitespace/indent"). Each filter should start with + or -; else we die. Raises: ValueError: The comma-separated filters did not all start with '+' or '-'. E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" """ # Default filters always have less priority than the flag ones. self.filters = _DEFAULT_FILTERS[:] for filt in filters.split(','): clean_filt = filt.strip() if clean_filt: self.filters.append(clean_filt) for filt in self.filters: if not (filt.startswith('+') or filt.startswith('-')): raise ValueError('Every filter in --filters must start with + or -' ' (%s does not)' % filt) def ResetErrorCounts(self): """Sets the module's error statistic back to zero.""" self.error_count = 0 self.errors_by_category = {} def IncrementErrorCount(self, category): """Bumps the module's error statistic.""" self.error_count += 1 if self.counting in ('toplevel', 'detailed'): if self.counting != 'detailed': category = category.split('/')[0] if category not in self.errors_by_category: self.errors_by_category[category] = 0 self.errors_by_category[category] += 1 def PrintErrorCounts(self): """Print a summary of errors by category, and the total.""" for category, count in self.errors_by_category.iteritems(): sys.stderr.write('Category \'%s\' errors found: %d\n' % (category, count)) sys.stderr.write('Total errors found: %d\n' % self.error_count) _cpplint_state = _CppLintState() def _OutputFormat(): """Gets the module's output format.""" return _cpplint_state.output_format def _SetOutputFormat(output_format): """Sets the module's output format.""" _cpplint_state.SetOutputFormat(output_format) def _VerboseLevel(): """Returns the module's verbosity setting.""" return _cpplint_state.verbose_level def _SetVerboseLevel(level): """Sets the module's verbosity, and returns the previous setting.""" return _cpplint_state.SetVerboseLevel(level) def _SetCountingStyle(level): """Sets the module's counting options.""" _cpplint_state.SetCountingStyle(level) def _Filters(): """Returns the module's list of output filters, as a list.""" return _cpplint_state.filters def _SetFilters(filters): """Sets the module's error-message filters. These filters are applied when deciding whether to emit a given error message. Args: filters: A string of comma-separated filters (eg "whitespace/indent"). Each filter should start with + or -; else we die. """ _cpplint_state.SetFilters(filters) class _FunctionState(object): """Tracks current function name and the number of lines in its body.""" _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. def __init__(self): self.in_a_function = False self.lines_in_function = 0 self.current_function = '' def Begin(self, function_name): """Start analyzing function body. Args: function_name: The name of the function being tracked. """ self.in_a_function = True self.lines_in_function = 0 self.current_function = function_name def Count(self): """Count line in current function body.""" if self.in_a_function: self.lines_in_function += 1 def Check(self, error, filename, linenum): """Report if too many lines in function body. Args: error: The function to call with any errors found. filename: The name of the current file. linenum: The number of the line to check. """ if Match(r'T(EST|est)', self.current_function): base_trigger = self._TEST_TRIGGER else: base_trigger = self._NORMAL_TRIGGER trigger = base_trigger * 2**_VerboseLevel() if self.lines_in_function > trigger: error_level = int(math.log(self.lines_in_function / base_trigger, 2)) # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... if error_level > 5: error_level = 5 error(filename, linenum, 'readability/fn_size', error_level, 'Small and focused functions are preferred:' ' %s has %d non-comment lines' ' (error triggered by exceeding %d lines).' % ( self.current_function, self.lines_in_function, trigger)) def End(self): """Stop analyzing function body.""" self.in_a_function = False class _IncludeError(Exception): """Indicates a problem with the include order in a file.""" pass class FileInfo: """Provides utility functions for filenames. FileInfo provides easy access to the components of a file's path relative to the project root. """ def __init__(self, filename): self._filename = filename def FullName(self): """Make Windows paths like Unix.""" return os.path.abspath(self._filename).replace('\\', '/') def RepositoryName(self): """FullName after removing the local path to the repository. If we have a real absolute path name here we can try to do something smart: detecting the root of the checkout and truncating /path/to/checkout from the name so that we get header guards that don't include things like "C:\Documents and Settings\..." or "/home/username/..." in them and thus people on different computers who have checked the source out to different locations won't see bogus errors. """ fullname = self.FullName() if os.path.exists(fullname): project_dir = os.path.dirname(fullname) if os.path.exists(os.path.join(project_dir, ".svn")): # If there's a .svn file in the current directory, we recursively look # up the directory tree for the top of the SVN checkout root_dir = project_dir one_up_dir = os.path.dirname(root_dir) while os.path.exists(os.path.join(one_up_dir, ".svn")): root_dir = os.path.dirname(root_dir) one_up_dir = os.path.dirname(one_up_dir) prefix = os.path.commonprefix([root_dir, project_dir]) return fullname[len(prefix) + 1:] # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by # searching up from the current path. root_dir = os.path.dirname(fullname) while (root_dir != os.path.dirname(root_dir) and not os.path.exists(os.path.join(root_dir, ".git")) and not os.path.exists(os.path.join(root_dir, ".hg")) and not os.path.exists(os.path.join(root_dir, ".svn"))): root_dir = os.path.dirname(root_dir) if (os.path.exists(os.path.join(root_dir, ".git")) or os.path.exists(os.path.join(root_dir, ".hg")) or os.path.exists(os.path.join(root_dir, ".svn"))): prefix = os.path.commonprefix([root_dir, project_dir]) return fullname[len(prefix) + 1:] # Don't know what to do; header guard warnings may be wrong... return fullname def Split(self): """Splits the file into the directory, basename, and extension. For 'chrome/browser/browser.cc', Split() would return ('chrome/browser', 'browser', '.cc') Returns: A tuple of (directory, basename, extension). """ googlename = self.RepositoryName() project, rest = os.path.split(googlename) return (project,) + os.path.splitext(rest) def BaseName(self): """File base name - text after the final slash, before the final period.""" return self.Split()[1] def Extension(self): """File extension - text following the final period.""" return self.Split()[2] def NoExtension(self): """File has no source file extension.""" return '/'.join(self.Split()[0:2]) def IsSource(self): """File has a source file extension.""" return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx') def _ShouldPrintError(category, confidence, linenum): """If confidence >= verbose, category passes filter and is not suppressed.""" # There are three ways we might decide not to print an error message: # a "NOLINT(category)" comment appears in the source, # the verbosity level isn't high enough, or the filters filter it out. if IsErrorSuppressedByNolint(category, linenum): return False if confidence < _cpplint_state.verbose_level: return False is_filtered = False for one_filter in _Filters(): if one_filter.startswith('-'): if category.startswith(one_filter[1:]): is_filtered = True elif one_filter.startswith('+'): if category.startswith(one_filter[1:]): is_filtered = False else: assert False # should have been checked for in SetFilter. if is_filtered: return False return True def Error(filename, linenum, category, confidence, message): """Logs the fact we've found a lint error. We log where the error was found, and also our confidence in the error, that is, how certain we are this is a legitimate style regression, and not a misidentification or a use that's sometimes justified. False positives can be suppressed by the use of "cpplint(category)" comments on the offending line. These are parsed into _error_suppressions. Args: filename: The name of the file containing the error. linenum: The number of the line containing the error. category: A string used to describe the "category" this bug falls under: "whitespace", say, or "runtime". Categories may have a hierarchy separated by slashes: "whitespace/indent". confidence: A number from 1-5 representing a confidence score for the error, with 5 meaning that we are certain of the problem, and 1 meaning that it could be a legitimate construct. message: The error message. """ if _ShouldPrintError(category, confidence, linenum): _cpplint_state.IncrementErrorCount(category) if _cpplint_state.output_format == 'vs7': sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( filename, linenum, message, category, confidence)) else: sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( filename, linenum, message, category, confidence)) # Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard. _RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') # Matches strings. Escape codes should already be removed by ESCAPES. _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"') # Matches characters. Escape codes should already be removed by ESCAPES. _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'") # Matches multi-line C++ comments. # This RE is a little bit more complicated than one might expect, because we # have to take care of space removals tools so we can handle comments inside # statements better. # The current rule is: We only clear spaces from both sides when we're at the # end of the line. Otherwise, we try to remove spaces from the right side, # if this doesn't work we try on left side but only if there's a non-character # on the right. _RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( r"""(\s*/\*.*\*/\s*$| /\*.*\*/\s+| \s+/\*.*\*/(?=\W)| /\*.*\*/)""", re.VERBOSE) def IsCppString(line): """Does line terminate so, that the next symbol is in string constant. This function does not consider single-line nor multi-line comments. Args: line: is a partial line of code starting from the 0..n. Returns: True, if next character appended to 'line' is inside a string constant. """ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 def FindNextMultiLineCommentStart(lines, lineix): """Find the beginning marker for a multiline comment.""" while lineix < len(lines): if lines[lineix].strip().startswith('/*'): # Only return this marker if the comment goes beyond this line if lines[lineix].strip().find('*/', 2) < 0: return lineix lineix += 1 return len(lines) def FindNextMultiLineCommentEnd(lines, lineix): """We are inside a comment, find the end marker.""" while lineix < len(lines): if lines[lineix].strip().endswith('*/'): return lineix lineix += 1 return len(lines) def RemoveMultiLineCommentsFromRange(lines, begin, end): """Clears a range of lines for multi-line comments.""" # Having // dummy comments makes the lines non-empty, so we will not get # unnecessary blank line warnings later in the code. for i in range(begin, end): lines[i] = '// dummy' def RemoveMultiLineComments(filename, lines, error): """Removes multiline (c-style) comments from lines.""" lineix = 0 while lineix < len(lines): lineix_begin = FindNextMultiLineCommentStart(lines, lineix) if lineix_begin >= len(lines): return lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) if lineix_end >= len(lines): error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, 'Could not find end of multi-line comment') return RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) lineix = lineix_end + 1 def CleanseComments(line): """Removes //-comments and single-line C-style /* */ comments. Args: line: A line of C++ source. Returns: The line with single-line comments removed. """ commentpos = line.find('//') if commentpos != -1 and not IsCppString(line[:commentpos]): line = line[:commentpos].rstrip() # get rid of /* ... */ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) class CleansedLines(object): """Holds 3 copies of all lines with different preprocessing applied to them. 1) elided member contains lines without strings and comments, 2) lines member contains lines without comments, and 3) raw member contains all the lines without processing. All these three members are of , and of the same length. """ def __init__(self, lines): self.elided = [] self.lines = [] self.raw_lines = lines self.num_lines = len(lines) for linenum in range(len(lines)): self.lines.append(CleanseComments(lines[linenum])) elided = self._CollapseStrings(lines[linenum]) self.elided.append(CleanseComments(elided)) def NumLines(self): """Returns the number of lines represented.""" return self.num_lines @staticmethod def _CollapseStrings(elided): """Collapses strings and chars on a line to simple "" or '' blocks. We nix strings first so we're not fooled by text like '"http://"' Args: elided: The line being processed. Returns: The line with collapsed strings. """ if not _RE_PATTERN_INCLUDE.match(elided): # Remove escaped characters first to make quote/single quote collapsing # basic. Things that look like escaped characters shouldn't occur # outside of strings and chars. elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided) elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided) return elided def CloseExpression(clean_lines, linenum, pos): """If input points to ( or { or [, finds the position that closes it. If lines[linenum][pos] points to a '(' or '{' or '[', finds the linenum/pos that correspond to the closing of the expression. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. pos: A position on the line. Returns: A tuple (line, linenum, pos) pointer *past* the closing brace, or (line, len(lines), -1) if we never find a close. Note we ignore strings and comments when matching; and the line we return is the 'cleansed' line at linenum. """ line = clean_lines.elided[linenum] startchar = line[pos] if startchar not in '({[': return (line, clean_lines.NumLines(), -1) if startchar == '(': endchar = ')' if startchar == '[': endchar = ']' if startchar == '{': endchar = '}' num_open = line.count(startchar) - line.count(endchar) while linenum < clean_lines.NumLines() and num_open > 0: linenum += 1 line = clean_lines.elided[linenum] num_open += line.count(startchar) - line.count(endchar) # OK, now find the endchar that actually got us back to even endpos = len(line) while num_open >= 0: endpos = line.rfind(')', 0, endpos) num_open -= 1 # chopped off another ) return (line, linenum, endpos + 1) def CheckForCopyright(filename, lines, error): """Logs an error if no Copyright message appears at the top of the file.""" # We'll say it should occur by line 10. Don't forget there's a # dummy line at the front. for line in xrange(1, min(len(lines), 11)): if re.search(r'Copyright', lines[line], re.I): break else: # means no copyright line was found error(filename, 0, 'legal/copyright', 5, 'No copyright message found. ' 'You should have a line: "Copyright [year] "') def GetHeaderGuardCPPVariable(filename): """Returns the CPP variable that should be used as a header guard. Args: filename: The name of a C++ header file. Returns: The CPP variable that should be used as a header guard in the named file. """ # Restores original filename in case that cpplint is invoked from Emacs's # flymake. filename = re.sub(r'_flymake\.h$', '.h', filename) fileinfo = FileInfo(filename) return re.sub(r'[-./\s]', '_', fileinfo.RepositoryName()).upper() + '_' def CheckForHeaderGuard(filename, lines, error): """Checks that the file contains a header guard. Logs an error if no #ifndef header guard is present. For other headers, checks that the full pathname is used. Args: filename: The name of the C++ header file. lines: An array of strings, each representing a line of the file. error: The function to call with any errors found. """ cppvar = GetHeaderGuardCPPVariable(filename) ifndef = None ifndef_linenum = 0 define = None endif = None endif_linenum = 0 for linenum, line in enumerate(lines): linesplit = line.split() if len(linesplit) >= 2: # find the first occurrence of #ifndef and #define, save arg if not ifndef and linesplit[0] == '#ifndef': # set ifndef to the header guard presented on the #ifndef line. ifndef = linesplit[1] ifndef_linenum = linenum if not define and linesplit[0] == '#define': define = linesplit[1] # find the last occurrence of #endif, save entire line if line.startswith('#endif'): endif = line endif_linenum = linenum if not ifndef: error(filename, 0, 'build/header_guard', 5, 'No #ifndef header guard found, suggested CPP variable is: %s' % cppvar) return if not define: error(filename, 0, 'build/header_guard', 5, 'No #define header guard found, suggested CPP variable is: %s' % cppvar) return # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ # for backward compatibility. if ifndef != cppvar: error_level = 0 if ifndef != cppvar + '_': error_level = 5 ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum, error) error(filename, ifndef_linenum, 'build/header_guard', error_level, '#ifndef header guard has wrong style, please use: %s' % cppvar) if define != ifndef: error(filename, 0, 'build/header_guard', 5, '#ifndef and #define don\'t match, suggested CPP variable is: %s' % cppvar) return if endif != ('#endif // %s' % cppvar): error_level = 0 if endif != ('#endif // %s' % (cppvar + '_')): error_level = 5 ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum, error) error(filename, endif_linenum, 'build/header_guard', error_level, '#endif line should be "#endif // %s"' % cppvar) def CheckForUnicodeReplacementCharacters(filename, lines, error): """Logs an error for each line containing Unicode replacement characters. These indicate that either the file contained invalid UTF-8 (likely) or Unicode replacement characters (which it shouldn't). Note that it's possible for this to throw off line numbering if the invalid UTF-8 occurred adjacent to a newline. Args: filename: The name of the current file. lines: An array of strings, each representing a line of the file. error: The function to call with any errors found. """ for linenum, line in enumerate(lines): if u'\ufffd' in line: error(filename, linenum, 'readability/utf8', 5, 'Line contains invalid UTF-8 (or Unicode replacement character).') def CheckForNewlineAtEOF(filename, lines, error): """Logs an error if there is no newline char at the end of the file. Args: filename: The name of the current file. lines: An array of strings, each representing a line of the file. error: The function to call with any errors found. """ # The array lines() was created by adding two newlines to the # original file (go figure), then splitting on \n. # To verify that the file ends in \n, we just have to make sure the # last-but-two element of lines() exists and is empty. if len(lines) < 3 or lines[-2]: error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, 'Could not find a newline character at the end of the file.') def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): """Logs an error if we see /* ... */ or "..." that extend past one line. /* ... */ comments are legit inside macros, for one line. Otherwise, we prefer // comments, so it's ok to warn about the other. Likewise, it's ok for strings to extend across multiple lines, as long as a line continuation character (backslash) terminates each line. Although not currently prohibited by the C++ style guide, it's ugly and unnecessary. We don't do well with either in this lint program, so we warn about both. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Remove all \\ (escaped backslashes) from the line. They are OK, and the # second (escaped) slash may trigger later \" detection erroneously. line = line.replace('\\\\', '') if line.count('/*') > line.count('*/'): error(filename, linenum, 'readability/multiline_comment', 5, 'Complex multi-line /*...*/-style comment found. ' 'Lint may give bogus warnings. ' 'Consider replacing these with //-style comments, ' 'with #if 0...#endif, ' 'or with more clearly structured multi-line comments.') if (line.count('"') - line.count('\\"')) % 2: error(filename, linenum, 'readability/multiline_string', 5, 'Multi-line string ("...") found. This lint script doesn\'t ' 'do well with such strings, and may give bogus warnings. They\'re ' 'ugly and unnecessary, and you should use concatenation instead".') threading_list = ( ('asctime(', 'asctime_r('), ('ctime(', 'ctime_r('), ('getgrgid(', 'getgrgid_r('), ('getgrnam(', 'getgrnam_r('), ('getlogin(', 'getlogin_r('), ('getpwnam(', 'getpwnam_r('), ('getpwuid(', 'getpwuid_r('), ('gmtime(', 'gmtime_r('), ('localtime(', 'localtime_r('), ('rand(', 'rand_r('), ('readdir(', 'readdir_r('), ('strtok(', 'strtok_r('), ('ttyname(', 'ttyname_r('), ) def CheckPosixThreading(filename, clean_lines, linenum, error): """Checks for calls to thread-unsafe functions. Much code has been originally written without consideration of multi-threading. Also, engineers are relying on their old experience; they have learned posix before threading extensions were added. These tests guide the engineers to use thread-safe functions (when using posix directly). Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] for single_thread_function, multithread_safe_function in threading_list: ix = line.find(single_thread_function) # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and line[ix - 1] not in ('_', '.', '>'))): error(filename, linenum, 'runtime/threadsafe_fn', 2, 'Consider using ' + multithread_safe_function + '...) instead of ' + single_thread_function + '...) for improved thread safety.') # Matches invalid increment: *count++, which moves pointer instead of # incrementing a value. _RE_PATTERN_INVALID_INCREMENT = re.compile( r'^\s*\*\w+(\+\+|--);') def CheckInvalidIncrement(filename, clean_lines, linenum, error): """Checks for invalid increment *count++. For example following function: void increment_counter(int* count) { *count++; } is invalid, because it effectively does count++, moving pointer, and should be replaced with ++*count, (*count)++ or *count += 1. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] if _RE_PATTERN_INVALID_INCREMENT.match(line): error(filename, linenum, 'runtime/invalid_increment', 5, 'Changing pointer instead of value (or unused value of operator*).') class _ClassInfo(object): """Stores information about a class.""" def __init__(self, name, clean_lines, linenum): self.name = name self.linenum = linenum self.seen_open_brace = False self.is_derived = False self.virtual_method_linenumber = None self.has_virtual_destructor = False self.brace_depth = 0 # Try to find the end of the class. This will be confused by things like: # class A { # } *x = { ... # # But it's still good enough for CheckSectionSpacing. self.last_line = 0 depth = 0 for i in range(linenum, clean_lines.NumLines()): line = clean_lines.lines[i] depth += line.count('{') - line.count('}') if not depth: self.last_line = i break class _ClassState(object): """Holds the current state of the parse relating to class declarations. It maintains a stack of _ClassInfos representing the parser's guess as to the current nesting of class declarations. The innermost class is at the top (back) of the stack. Typically, the stack will either be empty or have exactly one entry. """ def __init__(self): self.classinfo_stack = [] def CheckFinished(self, filename, error): """Checks that all classes have been completely parsed. Call this when all lines in a file have been processed. Args: filename: The name of the current file. error: The function to call with any errors found. """ if self.classinfo_stack: # Note: This test can result in false positives if #ifdef constructs # get in the way of brace matching. See the testBuildClass test in # cpplint_unittest.py for an example of this. error(filename, self.classinfo_stack[0].linenum, 'build/class', 5, 'Failed to find complete declaration of class %s' % self.classinfo_stack[0].name) def CheckForNonStandardConstructs(filename, clean_lines, linenum, class_state, error): """Logs an error if we see certain non-ANSI constructs ignored by gcc-2. Complain about several constructs which gcc-2 accepts, but which are not standard C++. Warning about these in lint is one way to ease the transition to new compilers. - put storage class first (e.g. "static const" instead of "const static"). - "%lld" instead of %qd" in printf-type functions. - "%1$d" is non-standard in printf-type functions. - "\%" is an undefined character escape sequence. - text after #endif is not allowed. - invalid inner-style forward declaration. - >? and ?= and )\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line): error(filename, linenum, 'build/deprecated', 3, '>? and ))?' # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' error(filename, linenum, 'runtime/member_string_references', 2, 'const string& members are dangerous. It is much better to use ' 'alternatives, such as pointers or simple constants.') # Track class entry and exit, and attempt to find cases within the # class declaration that don't meet the C++ style # guidelines. Tracking is very dependent on the code matching Google # style guidelines, but it seems to perform well enough in testing # to be a worthwhile addition to the checks. classinfo_stack = class_state.classinfo_stack # Look for a class declaration. The regexp accounts for decorated classes # such as in: # class LOCKABLE API Object { # }; class_decl_match = Match( r'\s*(template\s*<[\w\s<>,:]*>\s*)?' '(class|struct)\s+([A-Z_]+\s+)*(\w+(::\w+)*)', line) if class_decl_match: classinfo_stack.append(_ClassInfo( class_decl_match.group(4), clean_lines, linenum)) # Everything else in this function uses the top of the stack if it's # not empty. if not classinfo_stack: return classinfo = classinfo_stack[-1] # If the opening brace hasn't been seen look for it and also # parent class declarations. if not classinfo.seen_open_brace: # If the line has a ';' in it, assume it's a forward declaration or # a single-line class declaration, which we won't process. if line.find(';') != -1: classinfo_stack.pop() return classinfo.seen_open_brace = (line.find('{') != -1) # Look for a bare ':' if Search('(^|[^:]):($|[^:])', line): classinfo.is_derived = True if not classinfo.seen_open_brace: return # Everything else in this function is for after open brace # The class may have been declared with namespace or classname qualifiers. # The constructor and destructor will not have those qualifiers. base_classname = classinfo.name.split('::')[-1] # Look for single-argument constructors that aren't marked explicit. # Technically a valid construct, but against style. args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)' % re.escape(base_classname), line) if (args and args.group(1) != 'void' and not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname), args.group(1).strip())): error(filename, linenum, 'runtime/explicit', 5, 'Single-argument constructors should be marked explicit.') # Look for methods declared virtual. if Search(r'\bvirtual\b', line): classinfo.virtual_method_linenumber = linenum # Only look for a destructor declaration on the same line. It would # be extremely unlikely for the destructor declaration to occupy # more than one line. if Search(r'~%s\s*\(' % base_classname, line): classinfo.has_virtual_destructor = True # Look for class end. brace_depth = classinfo.brace_depth brace_depth = brace_depth + line.count('{') - line.count('}') if brace_depth <= 0: classinfo = classinfo_stack.pop() # Try to detect missing virtual destructor declarations. # For now, only warn if a non-derived class with virtual methods lacks # a virtual destructor. This is to make it less likely that people will # declare derived virtual destructors without declaring the base # destructor virtual. if ((classinfo.virtual_method_linenumber is not None) and (not classinfo.has_virtual_destructor) and (not classinfo.is_derived)): # Only warn for base classes error(filename, classinfo.linenum, 'runtime/virtual', 4, 'The class %s probably needs a virtual destructor due to ' 'having virtual method(s), one declared at line %d.' % (classinfo.name, classinfo.virtual_method_linenumber)) else: classinfo.brace_depth = brace_depth def CheckSpacingForFunctionCall(filename, line, linenum, error): """Checks for the correctness of various spacing around function calls. Args: filename: The name of the current file. line: The text of the line to check. linenum: The number of the line to check. error: The function to call with any errors found. """ # Since function calls often occur inside if/for/while/switch # expressions - which have their own, more liberal conventions - we # first see if we should be looking inside such an expression for a # function call, to which we can apply more strict standards. fncall = line # if there's no control flow construct, look at whole line for pattern in (r'\bif\s*\((.*)\)\s*{', r'\bfor\s*\((.*)\)\s*{', r'\bwhile\s*\((.*)\)\s*[{;]', r'\bswitch\s*\((.*)\)\s*{'): match = Search(pattern, line) if match: fncall = match.group(1) # look inside the parens for function calls break # Except in if/for/while/switch, there should never be space # immediately inside parens (eg "f( 3, 4 )"). We make an exception # for nested parens ( (a+b) + c ). Likewise, there should never be # a space before a ( when it's a function argument. I assume it's a # function argument when the char before the whitespace is legal in # a function name (alnum + _) and we're not starting a macro. Also ignore # pointers and references to arrays and functions coz they're too tricky: # we use a very simple way to recognize these: # " (something)(maybe-something)" or # " (something)(maybe-something," or # " (something)[something]" # Note that we assume the contents of [] to be short enough that # they'll never need to wrap. if ( # Ignore control structures. not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and # Ignore pointers/references to functions. not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and # Ignore pointers/references to arrays. not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call error(filename, linenum, 'whitespace/parens', 4, 'Extra space after ( in function call') elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): error(filename, linenum, 'whitespace/parens', 2, 'Extra space after (') if (Search(r'\w\s+\(', fncall) and not Search(r'#\s*define|typedef', fncall)): error(filename, linenum, 'whitespace/parens', 4, 'Extra space before ( in function call') # If the ) is followed only by a newline or a { + newline, assume it's # part of a control statement (if/while/etc), and don't complain if Search(r'[^)]\s+\)\s*[^{\s]', fncall): # If the closing parenthesis is preceded by only whitespaces, # try to give a more descriptive error message. if Search(r'^\s+\)', fncall): error(filename, linenum, 'whitespace/parens', 2, 'Closing ) should be moved to the previous line') else: error(filename, linenum, 'whitespace/parens', 2, 'Extra space before )') def IsBlankLine(line): """Returns true if the given line is blank. We consider a line to be blank if the line is empty or consists of only white spaces. Args: line: A line of a string. Returns: True, if the given line is blank. """ return not line or line.isspace() def CheckForFunctionLengths(filename, clean_lines, linenum, function_state, error): """Reports for long function bodies. For an overview why this is done, see: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions Uses a simplistic algorithm assuming other style guidelines (especially spacing) are followed. Only checks unindented functions, so class members are unchecked. Trivial bodies are unchecked, so constructors with huge initializer lists may be missed. Blank/comment lines are not counted so as to avoid encouraging the removal of vertical space and comments just to get through a lint check. NOLINT *on the last line of a function* disables this check. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. function_state: Current function name and lines in body so far. error: The function to call with any errors found. """ lines = clean_lines.lines line = lines[linenum] raw = clean_lines.raw_lines raw_line = raw[linenum] joined_line = '' starting_func = False regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... match_result = Match(regexp, line) if match_result: # If the name is all caps and underscores, figure it's a macro and # ignore it, unless it's TEST or TEST_F. function_name = match_result.group(1).split()[-1] if function_name == 'TEST' or function_name == 'TEST_F' or ( not Match(r'[A-Z_]+$', function_name)): starting_func = True if starting_func: body_found = False for start_linenum in xrange(linenum, clean_lines.NumLines()): start_line = lines[start_linenum] joined_line += ' ' + start_line.lstrip() if Search(r'(;|})', start_line): # Declarations and trivial functions body_found = True break # ... ignore elif Search(r'{', start_line): body_found = True function = Search(r'((\w|:)*)\(', line).group(1) if Match(r'TEST', function): # Handle TEST... macros parameter_regexp = Search(r'(\(.*\))', joined_line) if parameter_regexp: # Ignore bad syntax function += parameter_regexp.group(1) else: function += '()' function_state.Begin(function) break if not body_found: # No body for the function (or evidence of a non-function) was found. error(filename, linenum, 'readability/fn_size', 5, 'Lint failed to find start of function body.') elif Match(r'^\}\s*$', line): # function end function_state.Check(error, filename, linenum) function_state.End() elif not Match(r'^\s*$', line): function_state.Count() # Count non-blank/non-comment lines. _RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') def CheckComment(comment, filename, linenum, error): """Checks for common mistakes in TODO comments. Args: comment: The text of the comment from the line in question. filename: The name of the current file. linenum: The number of the line to check. error: The function to call with any errors found. """ match = _RE_PATTERN_TODO.match(comment) if match: # One whitespace is correct; zero whitespace is handled elsewhere. leading_whitespace = match.group(1) if len(leading_whitespace) > 1: error(filename, linenum, 'whitespace/todo', 2, 'Too many spaces before TODO') username = match.group(2) if not username: error(filename, linenum, 'readability/todo', 2, 'Missing username in TODO; it should look like ' '"// TODO(my_username): Stuff."') middle_whitespace = match.group(3) # Comparisons made explicit for correctness -- pylint: disable-msg=C6403 if middle_whitespace != ' ' and middle_whitespace != '': error(filename, linenum, 'whitespace/todo', 2, 'TODO(my_username) should be followed by a space') def CheckSpacing(filename, clean_lines, linenum, error): """Checks for the correctness of various spacing issues in the code. Things we check for: spaces around operators, spaces after if/for/while/switch, no spaces around parens in function calls, two spaces between code and comment, don't start a block with a blank line, don't end a function with a blank line, don't add a blank line after public/protected/private, don't have too many blank lines in a row. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ raw = clean_lines.raw_lines line = raw[linenum] # Before nixing comments, check if the line is blank for no good # reason. This includes the first line after a block is opened, and # blank lines at the end of a function (ie, right before a line like '}' if IsBlankLine(line): elided = clean_lines.elided prev_line = elided[linenum - 1] prevbrace = prev_line.rfind('{') # TODO(unknown): Don't complain if line before blank line, and line after, # both start with alnums and are indented the same amount. # This ignores whitespace at the start of a namespace block # because those are not usually indented. if (prevbrace != -1 and prev_line[prevbrace:].find('}') == -1 and prev_line[:prevbrace].find('namespace') == -1): # OK, we have a blank line at the start of a code block. Before we # complain, we check if it is an exception to the rule: The previous # non-empty line has the parameters of a function header that are indented # 4 spaces (because they did not fit in a 80 column line when placed on # the same line as the function name). We also check for the case where # the previous line is indented 6 spaces, which may happen when the # initializers of a constructor do not fit into a 80 column line. exception = False if Match(r' {6}\w', prev_line): # Initializer list? # We are looking for the opening column of initializer list, which # should be indented 4 spaces to cause 6 space indentation afterwards. search_position = linenum-2 while (search_position >= 0 and Match(r' {6}\w', elided[search_position])): search_position -= 1 exception = (search_position >= 0 and elided[search_position][:5] == ' :') else: # Search for the function arguments or an initializer list. We use a # simple heuristic here: If the line is indented 4 spaces; and we have a # closing paren, without the opening paren, followed by an opening brace # or colon (for initializer lists) we assume that it is the last line of # a function header. If we have a colon indented 4 spaces, it is an # initializer list. exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', prev_line) or Match(r' {4}:', prev_line)) if not exception: error(filename, linenum, 'whitespace/blank_line', 2, 'Blank line at the start of a code block. Is this needed?') # This doesn't ignore whitespace at the end of a namespace block # because that is too hard without pairing open/close braces; # however, a special exception is made for namespace closing # brackets which have a comment containing "namespace". # # Also, ignore blank lines at the end of a block in a long if-else # chain, like this: # if (condition1) { # // Something followed by a blank line # # } else if (condition2) { # // Something else # } if linenum + 1 < clean_lines.NumLines(): next_line = raw[linenum + 1] if (next_line and Match(r'\s*}', next_line) and next_line.find('namespace') == -1 and next_line.find('} else ') == -1): error(filename, linenum, 'whitespace/blank_line', 3, 'Blank line at the end of a code block. Is this needed?') matched = Match(r'\s*(public|protected|private):', prev_line) if matched: error(filename, linenum, 'whitespace/blank_line', 3, 'Do not leave a blank line after "%s:"' % matched.group(1)) # Next, we complain if there's a comment too near the text commentpos = line.find('//') if commentpos != -1: # Check if the // may be in quotes. If so, ignore it # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 if (line.count('"', 0, commentpos) - line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes # Allow one space for new scopes, two spaces otherwise: if (not Match(r'^\s*{ //', line) and ((commentpos >= 1 and line[commentpos-1] not in string.whitespace) or (commentpos >= 2 and line[commentpos-2] not in string.whitespace))): error(filename, linenum, 'whitespace/comments', 2, 'At least two spaces is best between code and comments') # There should always be a space between the // and the comment commentend = commentpos + 2 if commentend < len(line) and not line[commentend] == ' ': # but some lines are exceptions -- e.g. if they're big # comment delimiters like: # //---------------------------------------------------------- # or are an empty C++ style Doxygen comment, like: # /// # or they begin with multiple slashes followed by a space: # //////// Header comment match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or Search(r'^/$', line[commentend:]) or Search(r'^/+ ', line[commentend:])) if not match: error(filename, linenum, 'whitespace/comments', 4, 'Should have a space between // and comment') CheckComment(line[commentpos:], filename, linenum, error) line = clean_lines.elided[linenum] # get rid of comments and strings # Don't try to do spacing checks for operator methods line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". # Otherwise not. Note we only check for non-spaces on *both* sides; # sometimes people put non-spaces on one side when aligning ='s among # many lines (not that this is behavior that I approve of...) if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line): error(filename, linenum, 'whitespace/operators', 4, 'Missing spaces around =') # It's ok not to have spaces around binary operators like + - * /, but if # there's too little whitespace, we get concerned. It's hard to tell, # though, so we punt on this one for now. TODO. # You should always have whitespace around binary operators. # Alas, we can't test < or > because they're legitimately used sans spaces # (a->b, vector a). The only time we can tell is a < with no >, and # only if it's not template params list spilling into the next line. match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line) if not match: # Note that while it seems that the '<[^<]*' term in the following # regexp could be simplified to '<.*', which would indeed match # the same class of strings, the [^<] means that searching for the # regexp takes linear rather than quadratic time. if not Search(r'<[^<]*,\s*$', line): # template params spill match = Search(r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$', line) if match: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around %s' % match.group(1)) # We allow no-spaces around << and >> when used like this: 10<<20, but # not otherwise (particularly, not when used as streams) match = Search(r'[^0-9\s](<<|>>)[^0-9\s]', line) if match: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around %s' % match.group(1)) # There shouldn't be space around unary operators match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) if match: error(filename, linenum, 'whitespace/operators', 4, 'Extra space for operator %s' % match.group(1)) # A pet peeve of mine: no spaces after an if, while, switch, or for match = Search(r' (if\(|for\(|while\(|switch\()', line) if match: error(filename, linenum, 'whitespace/parens', 5, 'Missing space before ( in %s' % match.group(1)) # For if/for/while/switch, the left and right parens should be # consistent about how many spaces are inside the parens, and # there should either be zero or one spaces inside the parens. # We don't want: "if ( foo)" or "if ( foo )". # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. match = Search(r'\b(if|for|while|switch)\s*' r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', line) if match: if len(match.group(2)) != len(match.group(4)): if not (match.group(3) == ';' and len(match.group(2)) == 1 + len(match.group(4)) or not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): error(filename, linenum, 'whitespace/parens', 5, 'Mismatching spaces inside () in %s' % match.group(1)) if not len(match.group(2)) in [0, 1]: error(filename, linenum, 'whitespace/parens', 5, 'Should have zero or one spaces inside ( and ) in %s' % match.group(1)) # You should always have a space after a comma (either as fn arg or operator) if Search(r',[^\s]', line): error(filename, linenum, 'whitespace/comma', 3, 'Missing space after ,') # You should always have a space after a semicolon # except for few corner cases # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more # space after ; if Search(r';[^\s};\\)/]', line): error(filename, linenum, 'whitespace/semicolon', 3, 'Missing space after ;') # Next we will look for issues with function calls. CheckSpacingForFunctionCall(filename, line, linenum, error) # Except after an opening paren, or after another opening brace (in case of # an initializer list, for instance), you should have spaces before your # braces. And since you should never have braces at the beginning of a line, # this is an easy test. if Search(r'[^ ({]{', line): error(filename, linenum, 'whitespace/braces', 5, 'Missing space before {') # Make sure '} else {' has spaces. if Search(r'}else', line): error(filename, linenum, 'whitespace/braces', 5, 'Missing space before else') # You shouldn't have spaces before your brackets, except maybe after # 'delete []' or 'new char * []'. if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line): error(filename, linenum, 'whitespace/braces', 5, 'Extra space before [') # You shouldn't have a space before a semicolon at the end of the line. # There's a special case for "for" since the style guide allows space before # the semicolon there. if Search(r':\s*;\s*$', line): error(filename, linenum, 'whitespace/semicolon', 5, 'Semicolon defining empty statement. Use { } instead.') elif Search(r'^\s*;\s*$', line): error(filename, linenum, 'whitespace/semicolon', 5, 'Line contains only semicolon. If this should be an empty statement, ' 'use { } instead.') elif (Search(r'\s+;\s*$', line) and not Search(r'\bfor\b', line)): error(filename, linenum, 'whitespace/semicolon', 5, 'Extra space before last semicolon. If this should be an empty ' 'statement, use { } instead.') def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): """Checks for additional blank line issues related to sections. Currently the only thing checked here is blank line before protected/private. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. class_info: A _ClassInfo objects. linenum: The number of the line to check. error: The function to call with any errors found. """ # Skip checks if the class is small, where small means 25 lines or less. # 25 lines seems like a good cutoff since that's the usual height of # terminals, and any class that can't fit in one screen can't really # be considered "small". # # Also skip checks if we are on the first line. This accounts for # classes that look like # class Foo { public: ... }; # # If we didn't find the end of the class, last_line would be zero, # and the check will be skipped by the first condition. if (class_info.last_line - class_info.linenum <= 24 or linenum <= class_info.linenum): return matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) if matched: # Issue warning if the line before public/protected/private was # not a blank line, but don't do this if the previous line contains # "class" or "struct". This can happen two ways: # - We are at the beginning of the class. # - We are forward-declaring an inner class that is semantically # private, but needed to be public for implementation reasons. prev_line = clean_lines.lines[linenum - 1] if (not IsBlankLine(prev_line) and not Search(r'\b(class|struct)\b', prev_line)): # Try a bit harder to find the beginning of the class. This is to # account for multi-line base-specifier lists, e.g.: # class Derived # : public Base { end_class_head = class_info.linenum for i in range(class_info.linenum, linenum): if Search(r'\{\s*$', clean_lines.lines[i]): end_class_head = i break if end_class_head < linenum - 1: error(filename, linenum, 'whitespace/blank_line', 3, '"%s:" should be preceded by a blank line' % matched.group(1)) def GetPreviousNonBlankLine(clean_lines, linenum): """Return the most recent non-blank line and its line number. Args: clean_lines: A CleansedLines instance containing the file contents. linenum: The number of the line to check. Returns: A tuple with two elements. The first element is the contents of the last non-blank line before the current line, or the empty string if this is the first non-blank line. The second is the line number of that line, or -1 if this is the first non-blank line. """ prevlinenum = linenum - 1 while prevlinenum >= 0: prevline = clean_lines.elided[prevlinenum] if not IsBlankLine(prevline): # if not a blank line... return (prevline, prevlinenum) prevlinenum -= 1 return ('', -1) def CheckBraces(filename, clean_lines, linenum, error): """Looks for misplaced braces (e.g. at the end of line). Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # get rid of comments and strings if Match(r'\s*{\s*$', line): # We allow an open brace to start a line in the case where someone # is using braces in a block to explicitly create a new scope, # which is commonly used to control the lifetime of # stack-allocated variables. We don't detect this perfectly: we # just don't complain if the last non-whitespace character on the # previous non-blank line is ';', ':', '{', or '}'. prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] if not Search(r'[;:}{]\s*$', prevline): error(filename, linenum, 'whitespace/braces', 4, '{ should almost always be at the end of the previous line') # An else clause should be on the same line as the preceding closing brace. if Match(r'\s*else\s*', line): prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] if Match(r'\s*}\s*$', prevline): error(filename, linenum, 'whitespace/newline', 4, 'An else should appear on the same line as the preceding }') # If braces come on one side of an else, they should be on both. # However, we have to worry about "else if" that spans multiple lines! if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if # find the ( after the if pos = line.find('else if') pos = line.find('(', pos) if pos > 0: (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) if endline[endpos:].find('{') == -1: # must be brace after if error(filename, linenum, 'readability/braces', 5, 'If an else has a brace on one side, it should have it on both') else: # common case: else not followed by a multi-line if error(filename, linenum, 'readability/braces', 5, 'If an else has a brace on one side, it should have it on both') # Likewise, an else should never have the else clause on the same line if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): error(filename, linenum, 'whitespace/newline', 4, 'Else clause should never be on same line as else (use 2 lines)') # In the same way, a do/while should never be on one line if Match(r'\s*do [^\s{]', line): error(filename, linenum, 'whitespace/newline', 4, 'do/while clauses should not be on a single line') # Braces shouldn't be followed by a ; unless they're defining a struct # or initializing an array. # We can't tell in general, but we can for some common cases. prevlinenum = linenum while True: (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum) if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'): line = prevline + line else: break if (Search(r'{.*}\s*;', line) and line.count('{') == line.count('}') and not Search(r'struct|class|enum|\s*=\s*{', line)): error(filename, linenum, 'readability/braces', 4, "You don't need a ; after a }") def ReplaceableCheck(operator, macro, line): """Determine whether a basic CHECK can be replaced with a more specific one. For example suggest using CHECK_EQ instead of CHECK(a == b) and similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE. Args: operator: The C++ operator used in the CHECK. macro: The CHECK or EXPECT macro being called. line: The current source line. Returns: True if the CHECK can be replaced with a more specific one. """ # This matches decimal and hex integers, strings, and chars (in that order). match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')' # Expression to match two sides of the operator with something that # looks like a literal, since CHECK(x == iterator) won't compile. # This means we can't catch all the cases where a more specific # CHECK is possible, but it's less annoying than dealing with # extraneous warnings. match_this = (r'\s*' + macro + r'\((\s*' + match_constant + r'\s*' + operator + r'[^<>].*|' r'.*[^<>]' + operator + r'\s*' + match_constant + r'\s*\))') # Don't complain about CHECK(x == NULL) or similar because # CHECK_EQ(x, NULL) won't compile (requires a cast). # Also, don't complain about more complex boolean expressions # involving && or || such as CHECK(a == b || c == d). return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line) def CheckCheck(filename, clean_lines, linenum, error): """Checks the use of CHECK and EXPECT macros. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ # Decide the set of replacement macros that should be suggested raw_lines = clean_lines.raw_lines current_macro = '' for macro in _CHECK_MACROS: if raw_lines[linenum].find(macro) >= 0: current_macro = macro break if not current_macro: # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT' return line = clean_lines.elided[linenum] # get rid of comments and strings # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc. for operator in ['==', '!=', '>=', '>', '<=', '<']: if ReplaceableCheck(operator, current_macro, line): error(filename, linenum, 'readability/check', 2, 'Consider using %s instead of %s(a %s b)' % ( _CHECK_REPLACEMENT[current_macro][operator], current_macro, operator)) break def GetLineWidth(line): """Determines the width of the line in column positions. Args: line: A string, which may be a Unicode string. Returns: The width of the line in column positions, accounting for Unicode combining characters and wide characters. """ if isinstance(line, unicode): width = 0 for uc in unicodedata.normalize('NFC', line): if unicodedata.east_asian_width(uc) in ('W', 'F'): width += 2 elif not unicodedata.combining(uc): width += 1 return width else: return len(line) def CheckStyle(filename, clean_lines, linenum, file_extension, class_state, error): """Checks rules from the 'C++ style rules' section of cppguide.html. Most of these rules are hard to test (naming, comment style), but we do what we can. In particular we check for 2-space indents, line lengths, tab usage, spaces inside code, etc. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. file_extension: The extension (without the dot) of the filename. error: The function to call with any errors found. """ raw_lines = clean_lines.raw_lines line = raw_lines[linenum] if line.find('\t') != -1: error(filename, linenum, 'whitespace/tab', 1, 'Tab found; better to use spaces') # One or three blank spaces at the beginning of the line is weird; it's # hard to reconcile that with 2-space indents. # NOTE: here are the conditions rob pike used for his tests. Mine aren't # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces # if(RLENGTH > 20) complain = 0; # if(match($0, " +(error|private|public|protected):")) complain = 0; # if(match(prev, "&& *$")) complain = 0; # if(match(prev, "\\|\\| *$")) complain = 0; # if(match(prev, "[\",=><] *$")) complain = 0; # if(match($0, " <<")) complain = 0; # if(match(prev, " +for \\(")) complain = 0; # if(prevodd && match(prevprev, " +for \\(")) complain = 0; initial_spaces = 0 cleansed_line = clean_lines.elided[linenum] while initial_spaces < len(line) and line[initial_spaces] == ' ': initial_spaces += 1 if line and line[-1].isspace(): error(filename, linenum, 'whitespace/end_of_line', 4, 'Line ends in whitespace. Consider deleting these extra spaces.') # There are certain situations we allow one space, notably for labels elif ((initial_spaces == 1 or initial_spaces == 3) and not Match(r'\s*\w+\s*:\s*$', cleansed_line)): error(filename, linenum, 'whitespace/indent', 3, 'Weird number of spaces at line-start. ' 'Are you using a 2-space indent?') # Labels should always be indented at least one space. elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$', line): error(filename, linenum, 'whitespace/labels', 4, 'Labels should always be indented at least one space. ' 'If this is a member-initializer list in a constructor or ' 'the base class list in a class definition, the colon should ' 'be on the following line.') # Check if the line is a header guard. is_header_guard = False if file_extension == 'h': cppvar = GetHeaderGuardCPPVariable(filename) if (line.startswith('#ifndef %s' % cppvar) or line.startswith('#define %s' % cppvar) or line.startswith('#endif // %s' % cppvar)): is_header_guard = True # #include lines and header guards can be long, since there's no clean way to # split them. # # URLs can be long too. It's possible to split these, but it makes them # harder to cut&paste. # # The "$Id:...$" comment may also get very long without it being the # developers fault. if (not line.startswith('#include') and not is_header_guard and not Match(r'^\s*//.*http(s?)://\S*$', line) and not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): line_width = GetLineWidth(line) if line_width > 100: error(filename, linenum, 'whitespace/line_length', 4, 'Lines should very rarely be longer than 100 characters') elif line_width > 80: error(filename, linenum, 'whitespace/line_length', 2, 'Lines should be <= 80 characters long') if (cleansed_line.count(';') > 1 and # for loops are allowed two ;'s (and may run over two lines). cleansed_line.find('for') == -1 and (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and # It's ok to have many commands in a switch case that fits in 1 line not ((cleansed_line.find('case ') != -1 or cleansed_line.find('default:') != -1) and cleansed_line.find('break;') != -1)): error(filename, linenum, 'whitespace/newline', 4, 'More than one command on the same line') # Some more style checks CheckBraces(filename, clean_lines, linenum, error) CheckSpacing(filename, clean_lines, linenum, error) CheckCheck(filename, clean_lines, linenum, error) if class_state and class_state.classinfo_stack: CheckSectionSpacing(filename, clean_lines, class_state.classinfo_stack[-1], linenum, error) _RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') _RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') # Matches the first component of a filename delimited by -s and _s. That is: # _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' _RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') def _DropCommonSuffixes(filename): """Drops common suffixes like _test.cc or -inl.h from filename. For example: >>> _DropCommonSuffixes('foo/foo-inl.h') 'foo/foo' >>> _DropCommonSuffixes('foo/bar/foo.cc') 'foo/bar/foo' >>> _DropCommonSuffixes('foo/foo_internal.h') 'foo/foo' >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') 'foo/foo_unusualinternal' Args: filename: The input filename. Returns: The filename with the common suffix removed. """ for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 'inl.h', 'impl.h', 'internal.h'): if (filename.endswith(suffix) and len(filename) > len(suffix) and filename[-len(suffix) - 1] in ('-', '_')): return filename[:-len(suffix) - 1] return os.path.splitext(filename)[0] def _IsTestFilename(filename): """Determines if the given filename has a suffix that identifies it as a test. Args: filename: The input filename. Returns: True if 'filename' looks like a test, False otherwise. """ if (filename.endswith('_test.cc') or filename.endswith('_unittest.cc') or filename.endswith('_regtest.cc')): return True else: return False def _ClassifyInclude(fileinfo, include, is_system): """Figures out what kind of header 'include' is. Args: fileinfo: The current file cpplint is running over. A FileInfo instance. include: The path to a #included file. is_system: True if the #include used <> rather than "". Returns: One of the _XXX_HEADER constants. For example: >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) _C_SYS_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) _CPP_SYS_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) _LIKELY_MY_HEADER >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), ... 'bar/foo_other_ext.h', False) _POSSIBLE_MY_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) _OTHER_HEADER """ # This is a list of all standard c++ header files, except # those already checked for above. is_stl_h = include in _STL_HEADERS is_cpp_h = is_stl_h or include in _CPP_HEADERS if is_system: if is_cpp_h: return _CPP_SYS_HEADER else: return _C_SYS_HEADER # If the target file and the include we're checking share a # basename when we drop common extensions, and the include # lives in . , then it's likely to be owned by the target file. target_dir, target_base = ( os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) if target_base == include_base and ( include_dir == target_dir or include_dir == os.path.normpath(target_dir + '/../public')): return _LIKELY_MY_HEADER # If the target and include share some initial basename # component, it's possible the target is implementing the # include, so it's allowed to be first, but we'll never # complain if it's not there. target_first_component = _RE_FIRST_COMPONENT.match(target_base) include_first_component = _RE_FIRST_COMPONENT.match(include_base) if (target_first_component and include_first_component and target_first_component.group(0) == include_first_component.group(0)): return _POSSIBLE_MY_HEADER return _OTHER_HEADER def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): """Check rules that are applicable to #include lines. Strings on #include lines are NOT removed from elided line, to make certain tasks easier. However, to prevent false positives, checks applicable to #include lines in CheckLanguage must be put here. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. include_state: An _IncludeState instance in which the headers are inserted. error: The function to call with any errors found. """ fileinfo = FileInfo(filename) line = clean_lines.lines[linenum] # "include" should use the new style "foo/bar.h" instead of just "bar.h" if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line): error(filename, linenum, 'build/include', 4, 'Include the directory when naming .h files') # we shouldn't include a file more than once. actually, there are a # handful of instances where doing so is okay, but in general it's # not. match = _RE_PATTERN_INCLUDE.search(line) if match: include = match.group(2) is_system = (match.group(1) == '<') if include in include_state: error(filename, linenum, 'build/include', 4, '"%s" already included at %s:%s' % (include, filename, include_state[include])) else: include_state[include] = linenum # We want to ensure that headers appear in the right order: # 1) for foo.cc, foo.h (preferred location) # 2) c system files # 3) cpp system files # 4) for foo.cc, foo.h (deprecated location) # 5) other google headers # # We classify each include statement as one of those 5 types # using a number of techniques. The include_state object keeps # track of the highest type seen, and complains if we see a # lower type after that. error_message = include_state.CheckNextIncludeOrder( _ClassifyInclude(fileinfo, include, is_system)) if error_message: error(filename, linenum, 'build/include_order', 4, '%s. Should be: %s.h, c system, c++ system, other.' % (error_message, fileinfo.BaseName())) if not include_state.IsInAlphabeticalOrder(include): error(filename, linenum, 'build/include_alpha', 4, 'Include "%s" not in alphabetical order' % include) # Look for any of the stream classes that are part of standard C++. match = _RE_PATTERN_INCLUDE.match(line) if match: include = match.group(2) if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): # Many unit tests use cout, so we exempt them. if not _IsTestFilename(filename): error(filename, linenum, 'readability/streams', 3, 'Streams are highly discouraged.') def _GetTextInside(text, start_pattern): """Retrieves all the text between matching open and close parentheses. Given a string of lines and a regular expression string, retrieve all the text following the expression and between opening punctuation symbols like (, [, or {, and the matching close-punctuation symbol. This properly nested occurrences of the punctuations, so for the text like printf(a(), b(c())); a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. start_pattern must match string having an open punctuation symbol at the end. Args: text: The lines to extract text. Its comments and strings must be elided. It can be single line and can span multiple lines. start_pattern: The regexp string indicating where to start extracting the text. Returns: The extracted text. None if either the opening string or ending punctuation could not be found. """ # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably # rewritten to use _GetTextInside (and use inferior regexp matching today). # Give opening punctuations to get the matching close-punctuations. matching_punctuation = {'(': ')', '{': '}', '[': ']'} closing_punctuation = set(matching_punctuation.itervalues()) # Find the position to start extracting text. match = re.search(start_pattern, text, re.M) if not match: # start_pattern not found in text. return None start_position = match.end(0) assert start_position > 0, ( 'start_pattern must ends with an opening punctuation.') assert text[start_position - 1] in matching_punctuation, ( 'start_pattern must ends with an opening punctuation.') # Stack of closing punctuations we expect to have in text after position. punctuation_stack = [matching_punctuation[text[start_position - 1]]] position = start_position while punctuation_stack and position < len(text): if text[position] == punctuation_stack[-1]: punctuation_stack.pop() elif text[position] in closing_punctuation: # A closing punctuation without matching opening punctuations. return None elif text[position] in matching_punctuation: punctuation_stack.append(matching_punctuation[text[position]]) position += 1 if punctuation_stack: # Opening punctuations left without matching close-punctuations. return None # punctuations match. return text[start_position:position - 1] def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state, error): """Checks rules from the 'C++ language rules' section of cppguide.html. Some of these rules are hard to test (function overloading, using uint32 inappropriately), but we do the best we can. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. file_extension: The extension (without the dot) of the filename. include_state: An _IncludeState instance in which the headers are inserted. error: The function to call with any errors found. """ # If the line is empty or consists of entirely a comment, no need to # check it. line = clean_lines.elided[linenum] if not line: return match = _RE_PATTERN_INCLUDE.search(line) if match: CheckIncludeLine(filename, clean_lines, linenum, include_state, error) return # Create an extended_line, which is the concatenation of the current and # next lines, for more effective checking of code that may span more than one # line. if linenum + 1 < clean_lines.NumLines(): extended_line = line + clean_lines.elided[linenum + 1] else: extended_line = line # Make Windows paths like Unix. fullname = os.path.abspath(filename).replace('\\', '/') # TODO(unknown): figure out if they're using default arguments in fn proto. # Check for non-const references in functions. This is tricky because & # is also used to take the address of something. We allow <> for templates, # (ignoring whatever is between the braces) and : for classes. # These are complicated re's. They try to capture the following: # paren (for fn-prototype start), typename, &, varname. For the const # version, we're willing for const to be before typename or after # Don't check the implementation on same line. fnline = line.split('{', 1)[0] if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) > len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?' r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) + len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+', fnline))): # We allow non-const references in a few standard places, like functions # called "swap()" or iostream operators like "<<" or ">>". if not Search( r'(swap|Swap|operator[<>][<>])\s*\(\s*(?:[\w:]|<.*>)+\s*&', fnline): error(filename, linenum, 'runtime/references', 2, 'Is this a non-const reference? ' 'If so, make const or use a pointer.') # Check to see if they're using an conversion function cast. # I just try to capture the most common basic types, though there are more. # Parameterless conversion functions, such as bool(), are allowed as they are # probably a member operator declaration or default constructor. match = Search( r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line) if match: # gMock methods are defined using some variant of MOCK_METHODx(name, type) # where type may be float(), int(string), etc. Without context they are # virtually indistinguishable from int(x) casts. Likewise, gMock's # MockCallback takes a template parameter of the form return_type(arg_type), # which looks much like the cast we're trying to detect. if (match.group(1) is None and # If new operator, then this isn't a cast not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or Match(r'^\s*MockCallback<.*>', line))): error(filename, linenum, 'readability/casting', 4, 'Using deprecated casting style. ' 'Use static_cast<%s>(...) instead' % match.group(2)) CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 'static_cast', r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) # This doesn't catch all cases. Consider (const char * const)"hello". # # (char *) "foo" should always be a const_cast (reinterpret_cast won't # compile). if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error): pass else: # Check pointer casts for other than string constants CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) # In addition, we look for people taking the address of a cast. This # is dangerous -- casts can assign to temporaries, so the pointer doesn't # point where you think. if Search( r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line): error(filename, linenum, 'runtime/casting', 4, ('Are you taking an address of a cast? ' 'This is dangerous: could be a temp var. ' 'Take the address before doing the cast, rather than after')) # Check for people declaring static/global STL strings at the top level. # This is dangerous because the C++ language does not guarantee that # globals with constructors are initialized before the first access. match = Match( r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)', line) # Make sure it's not a function. # Function template specialization looks like: "string foo(...". # Class template definitions look like: "string Foo::Method(...". if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)', match.group(3)): error(filename, linenum, 'runtime/string', 4, 'For a static/global string constant, use a C style string instead: ' '"%schar %s[]".' % (match.group(1), match.group(2))) # Check that we're not using RTTI outside of testing code. if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename): error(filename, linenum, 'runtime/rtti', 5, 'Do not use dynamic_cast<>. If you need to cast within a class ' "hierarchy, use static_cast<> to upcast. Google doesn't support " 'RTTI.') if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line): error(filename, linenum, 'runtime/init', 4, 'You seem to be initializing a member variable with itself.') if file_extension == 'h': # TODO(unknown): check that 1-arg constructors are explicit. # How to tell it's a constructor? # (handled in CheckForNonStandardConstructs for now) # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS # (level 1 error) pass # Check if people are using the verboten C basic types. The only exception # we regularly allow is "unsigned short port" for port. if Search(r'\bshort port\b', line): if not Search(r'\bunsigned short port\b', line): error(filename, linenum, 'runtime/int', 4, 'Use "unsigned short" for ports, not "short"') else: match = Search(r'\b(short|long(?! +double)|long long)\b', line) if match: error(filename, linenum, 'runtime/int', 4, 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) # When snprintf is used, the second argument shouldn't be a literal. match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) if match and match.group(2) != '0': # If 2nd arg is zero, snprintf is used to calculate size. error(filename, linenum, 'runtime/printf', 3, 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' 'to snprintf.' % (match.group(1), match.group(2))) # Check if some verboten C functions are being used. if Search(r'\bsprintf\b', line): error(filename, linenum, 'runtime/printf', 5, 'Never use sprintf. Use snprintf instead.') match = Search(r'\b(strcpy|strcat)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, 'Almost always, snprintf is better than %s' % match.group(1)) if Search(r'\bsscanf\b', line): error(filename, linenum, 'runtime/printf', 1, 'sscanf can be ok, but is slow and can overflow buffers.') # Check if some verboten operator overloading is going on # TODO(unknown): catch out-of-line unary operator&: # class X {}; # int operator&(const X& x) { return 42; } // unary operator& # The trick is it's hard to tell apart from binary operator&: # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& if Search(r'\boperator\s*&\s*\(\s*\)', line): error(filename, linenum, 'runtime/operator', 4, 'Unary operator& is dangerous. Do not use it.') # Check for suspicious usage of "if" like # } if (a == b) { if Search(r'\}\s*if\s*\(', line): error(filename, linenum, 'readability/braces', 4, 'Did you mean "else if"? If not, start a new line for "if".') # Check for potential format string bugs like printf(foo). # We constrain the pattern not to pick things like DocidForPrintf(foo). # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) # TODO(sugawarayu): Catch the following case. Need to change the calling # convention of the whole function to process multiple line to handle it. # printf( # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') if printf_args: match = Match(r'([\w.\->()]+)$', printf_args) if match: function_name = re.search(r'\b((?:string)?printf)\s*\(', line, re.I).group(1) error(filename, linenum, 'runtime/printf', 4, 'Potential format string bug. Do %s("%%s", %s) instead.' % (function_name, match.group(1))) # Check for potential memset bugs like memset(buf, sizeof(buf), 0). match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): error(filename, linenum, 'runtime/memset', 4, 'Did you mean "memset(%s, 0, %s)"?' % (match.group(1), match.group(2))) if Search(r'\busing namespace\b', line): error(filename, linenum, 'build/namespaces', 5, 'Do not use namespace using-directives. ' 'Use using-declarations instead.') # Detect variable-length arrays. match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) if (match and match.group(2) != 'return' and match.group(2) != 'delete' and match.group(3).find(']') == -1): # Split the size using space and arithmetic operators as delimiters. # If any of the resulting tokens are not compile time constants then # report the error. tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) is_const = True skip_next = False for tok in tokens: if skip_next: skip_next = False continue if Search(r'sizeof\(.+\)', tok): continue if Search(r'arraysize\(\w+\)', tok): continue tok = tok.lstrip('(') tok = tok.rstrip(')') if not tok: continue if Match(r'\d+', tok): continue if Match(r'0[xX][0-9a-fA-F]+', tok): continue if Match(r'k[A-Z0-9]\w*', tok): continue if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue # A catch all for tricky sizeof cases, including 'sizeof expression', # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' # requires skipping the next token because we split on ' ' and '*'. if tok.startswith('sizeof'): skip_next = True continue is_const = False break if not is_const: error(filename, linenum, 'runtime/arrays', 1, 'Do not use variable-length arrays. Use an appropriately named ' "('k' followed by CamelCase) compile-time constant for the size.") # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing # in the class declaration. match = Match( (r'\s*' r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))' r'\(.*\);$'), line) if match and linenum + 1 < clean_lines.NumLines(): next_line = clean_lines.elided[linenum + 1] # We allow some, but not all, declarations of variables to be present # in the statement that defines the class. The [\w\*,\s]* fragment of # the regular expression below allows users to declare instances of # the class or pointers to instances, but not less common types such # as function pointers or arrays. It's a tradeoff between allowing # reasonable code and avoiding trying to parse more C++ using regexps. if not Search(r'^\s*}[\w\*,\s]*;', next_line): error(filename, linenum, 'readability/constructors', 3, match.group(1) + ' should be the last thing in the class') # Check for use of unnamed namespaces in header files. Registration # macros are typically OK, so we allow use of "namespace {" on lines # that end with backslashes. if (file_extension == 'h' and Search(r'\bnamespace\s*{', line) and line[-1] != '\\'): error(filename, linenum, 'build/namespaces', 4, 'Do not use unnamed namespaces in header files. See ' 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' ' for more information.') def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern, error): """Checks for a C-style cast by looking for the pattern. This also handles sizeof(type) warnings, due to similarity of content. Args: filename: The name of the current file. linenum: The number of the line to check. line: The line of code to check. raw_line: The raw line of code to check, with comments. cast_type: The string for the C++ cast to recommend. This is either reinterpret_cast, static_cast, or const_cast, depending. pattern: The regular expression used to find C-style casts. error: The function to call with any errors found. Returns: True if an error was emitted. False otherwise. """ match = Search(pattern, line) if not match: return False # e.g., sizeof(int) sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1]) if sizeof_match: error(filename, linenum, 'runtime/sizeof', 1, 'Using sizeof(type). Use sizeof(varname) instead if possible') return True remainder = line[match.end(0):] # The close paren is for function pointers as arguments to a function. # eg, void foo(void (*bar)(int)); # The semicolon check is a more basic function check; also possibly a # function pointer typedef. # eg, void foo(int); or void foo(int) const; # The equals check is for function pointer assignment. # eg, void *(*foo)(int) = ... # The > is for MockCallback<...> ... # # Right now, this will only catch cases where there's a single argument, and # it's unnamed. It should probably be expanded to check for multiple # arguments with some unnamed. function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder) if function_match: if (not function_match.group(3) or function_match.group(3) == ';' or ('MockCallback<' not in raw_line and '/*' not in raw_line)): error(filename, linenum, 'readability/function', 3, 'All parameters should be named in a function') return True # At this point, all that should be left is actual casts. error(filename, linenum, 'readability/casting', 4, 'Using C-style cast. Use %s<%s>(...) instead' % (cast_type, match.group(1))) return True _HEADERS_CONTAINING_TEMPLATES = ( ('', ('deque',)), ('', ('unary_function', 'binary_function', 'plus', 'minus', 'multiplies', 'divides', 'modulus', 'negate', 'equal_to', 'not_equal_to', 'greater', 'less', 'greater_equal', 'less_equal', 'logical_and', 'logical_or', 'logical_not', 'unary_negate', 'not1', 'binary_negate', 'not2', 'bind1st', 'bind2nd', 'pointer_to_unary_function', 'pointer_to_binary_function', 'ptr_fun', 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 'mem_fun_ref_t', 'const_mem_fun_t', 'const_mem_fun1_t', 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 'mem_fun_ref', )), ('', ('numeric_limits',)), ('', ('list',)), ('', ('map', 'multimap',)), ('', ('allocator',)), ('', ('queue', 'priority_queue',)), ('', ('set', 'multiset',)), ('', ('stack',)), ('', ('char_traits', 'basic_string',)), ('', ('pair',)), ('', ('vector',)), # gcc extensions. # Note: std::hash is their hash, ::hash is our hash ('', ('hash_map', 'hash_multimap',)), ('', ('hash_set', 'hash_multiset',)), ('', ('slist',)), ) _RE_PATTERN_STRING = re.compile(r'\bstring\b') _re_pattern_algorithm_header = [] for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap', 'transform'): # Match max(..., ...), max(..., ...), but not foo->max, foo.max or # type::max(). _re_pattern_algorithm_header.append( (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), _template, '')) _re_pattern_templates = [] for _header, _templates in _HEADERS_CONTAINING_TEMPLATES: for _template in _templates: _re_pattern_templates.append( (re.compile(r'(\<|\b)' + _template + r'\s*\<'), _template + '<>', _header)) def FilesBelongToSameModule(filename_cc, filename_h): """Check if these two filenames belong to the same module. The concept of a 'module' here is a as follows: foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the same 'module' if they are in the same directory. some/path/public/xyzzy and some/path/internal/xyzzy are also considered to belong to the same module here. If the filename_cc contains a longer path than the filename_h, for example, '/absolute/path/to/base/sysinfo.cc', and this file would include 'base/sysinfo.h', this function also produces the prefix needed to open the header. This is used by the caller of this function to more robustly open the header file. We don't have access to the real include paths in this context, so we need this guesswork here. Known bugs: tools/base/bar.cc and base/bar.h belong to the same module according to this implementation. Because of this, this function gives some false positives. This should be sufficiently rare in practice. Args: filename_cc: is the path for the .cc file filename_h: is the path for the header path Returns: Tuple with a bool and a string: bool: True if filename_cc and filename_h belong to the same module. string: the additional prefix needed to open the header file. """ if not filename_cc.endswith('.cc'): return (False, '') filename_cc = filename_cc[:-len('.cc')] if filename_cc.endswith('_unittest'): filename_cc = filename_cc[:-len('_unittest')] elif filename_cc.endswith('_test'): filename_cc = filename_cc[:-len('_test')] filename_cc = filename_cc.replace('/public/', '/') filename_cc = filename_cc.replace('/internal/', '/') if not filename_h.endswith('.h'): return (False, '') filename_h = filename_h[:-len('.h')] if filename_h.endswith('-inl'): filename_h = filename_h[:-len('-inl')] filename_h = filename_h.replace('/public/', '/') filename_h = filename_h.replace('/internal/', '/') files_belong_to_same_module = filename_cc.endswith(filename_h) common_path = '' if files_belong_to_same_module: common_path = filename_cc[:-len(filename_h)] return files_belong_to_same_module, common_path def UpdateIncludeState(filename, include_state, io=codecs): """Fill up the include_state with new includes found from the file. Args: filename: the name of the header to read. include_state: an _IncludeState instance in which the headers are inserted. io: The io factory to use to read the file. Provided for testability. Returns: True if a header was succesfully added. False otherwise. """ headerfile = None try: headerfile = io.open(filename, 'r', 'utf8', 'replace') except IOError: return False linenum = 0 for line in headerfile: linenum += 1 clean_line = CleanseComments(line) match = _RE_PATTERN_INCLUDE.search(clean_line) if match: include = match.group(2) # The value formatting is cute, but not really used right now. # What matters here is that the key is in include_state. include_state.setdefault(include, '%s:%d' % (filename, linenum)) return True def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs): """Reports for missing stl includes. This function will output warnings to make sure you are including the headers necessary for the stl containers and functions that you use. We only give one reason to include a header. For example, if you use both equal_to<> and less<> in a .h file, only one (the latter in the file) of these will be reported as a reason to include the . Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. include_state: An _IncludeState instance. error: The function to call with any errors found. io: The IO factory to use to read the header file. Provided for unittest injection. """ required = {} # A map of header name to linenumber and the template entity. # Example of required: { '': (1219, 'less<>') } for linenum in xrange(clean_lines.NumLines()): line = clean_lines.elided[linenum] if not line or line[0] == '#': continue # String is special -- it is a non-templatized type in STL. matched = _RE_PATTERN_STRING.search(line) if matched: # Don't warn about strings in non-STL namespaces: # (We check only the first match per line; good enough.) prefix = line[:matched.start()] if prefix.endswith('std::') or not prefix.endswith('::'): required[''] = (linenum, 'string') for pattern, template, header in _re_pattern_algorithm_header: if pattern.search(line): required[header] = (linenum, template) # The following function is just a speed up, no semantics are changed. if not '<' in line: # Reduces the cpu time usage by skipping lines. continue for pattern, template, header in _re_pattern_templates: if pattern.search(line): required[header] = (linenum, template) # The policy is that if you #include something in foo.h you don't need to # include it again in foo.cc. Here, we will look at possible includes. # Let's copy the include_state so it is only messed up within this function. include_state = include_state.copy() # Did we find the header for this file (if any) and succesfully load it? header_found = False # Use the absolute path so that matching works properly. abs_filename = FileInfo(filename).FullName() # For Emacs's flymake. # If cpplint is invoked from Emacs's flymake, a temporary file is generated # by flymake and that file name might end with '_flymake.cc'. In that case, # restore original file name here so that the corresponding header file can be # found. # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' # instead of 'foo_flymake.h' abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) # include_state is modified during iteration, so we iterate over a copy of # the keys. header_keys = include_state.keys() for header in header_keys: (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) fullpath = common_path + header if same_module and UpdateIncludeState(fullpath, include_state, io): header_found = True # If we can't find the header file for a .cc, assume it's because we don't # know where to look. In that case we'll give up as we're not sure they # didn't include it in the .h file. # TODO(unknown): Do a better job of finding .h files so we are confident that # not having the .h file means there isn't one. if filename.endswith('.cc') and not header_found: return # All the lines have been processed, report the errors found. for required_header_unstripped in required: template = required[required_header_unstripped][1] if required_header_unstripped.strip('<>"') not in include_state: error(filename, required[required_header_unstripped][0], 'build/include_what_you_use', 4, 'Add #include ' + required_header_unstripped + ' for ' + template) _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): """Check that make_pair's template arguments are deduced. G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are specified explicitly, and such use isn't intended in any case. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ raw = clean_lines.raw_lines line = raw[linenum] match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) if match: error(filename, linenum, 'build/explicit_make_pair', 4, # 4 = high confidence 'Omit template arguments from make_pair OR use pair directly OR' ' if appropriate, construct a pair directly') def ProcessLine(filename, file_extension, clean_lines, line, include_state, function_state, class_state, error, extra_check_functions=[]): """Processes a single line in the file. Args: filename: Filename of the file that is being processed. file_extension: The extension (dot not included) of the file. clean_lines: An array of strings, each representing a line of the file, with comments stripped. line: Number of line being processed. include_state: An _IncludeState instance in which the headers are inserted. function_state: A _FunctionState instance which counts function lines, etc. class_state: A _ClassState instance which maintains information about the current stack of nested class declarations being parsed. error: A callable to which errors are reported, which takes 4 arguments: filename, line number, error level, and message extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ raw_lines = clean_lines.raw_lines ParseNolintSuppressions(filename, raw_lines[line], line, error) CheckForFunctionLengths(filename, clean_lines, line, function_state, error) CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) CheckStyle(filename, clean_lines, line, file_extension, class_state, error) CheckLanguage(filename, clean_lines, line, file_extension, include_state, error) CheckForNonStandardConstructs(filename, clean_lines, line, class_state, error) CheckPosixThreading(filename, clean_lines, line, error) CheckInvalidIncrement(filename, clean_lines, line, error) CheckMakePairUsesDeduction(filename, clean_lines, line, error) for check_fn in extra_check_functions: check_fn(filename, clean_lines, line, error) def ProcessFileData(filename, file_extension, lines, error, extra_check_functions=[]): """Performs lint checks and reports any errors to the given error function. Args: filename: Filename of the file that is being processed. file_extension: The extension (dot not included) of the file. lines: An array of strings, each representing a line of the file, with the last element being empty if the file is terminated with a newline. error: A callable to which errors are reported, which takes 4 arguments: filename, line number, error level, and message extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ lines = (['// marker so line numbers and indices both start at 1'] + lines + ['// marker so line numbers end in a known way']) include_state = _IncludeState() function_state = _FunctionState() class_state = _ClassState() ResetNolintSuppressions() CheckForCopyright(filename, lines, error) if file_extension == 'h': CheckForHeaderGuard(filename, lines, error) RemoveMultiLineComments(filename, lines, error) clean_lines = CleansedLines(lines) for line in xrange(clean_lines.NumLines()): ProcessLine(filename, file_extension, clean_lines, line, include_state, function_state, class_state, error, extra_check_functions) class_state.CheckFinished(filename, error) CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) # We check here rather than inside ProcessLine so that we see raw # lines rather than "cleaned" lines. CheckForUnicodeReplacementCharacters(filename, lines, error) CheckForNewlineAtEOF(filename, lines, error) def ProcessFile(filename, vlevel, extra_check_functions=[]): """Does google-lint on a single file. Args: filename: The name of the file to parse. vlevel: The level of errors to report. Every error of confidence >= verbose_level will be reported. 0 is a good default. extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ _SetVerboseLevel(vlevel) try: # Support the UNIX convention of using "-" for stdin. Note that # we are not opening the file with universal newline support # (which codecs doesn't support anyway), so the resulting lines do # contain trailing '\r' characters if we are reading a file that # has CRLF endings. # If after the split a trailing '\r' is present, it is removed # below. If it is not expected to be present (i.e. os.linesep != # '\r\n' as in Windows), a warning is issued below if this file # is processed. if filename == '-': lines = codecs.StreamReaderWriter(sys.stdin, codecs.getreader('utf8'), codecs.getwriter('utf8'), 'replace').read().split('\n') else: lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') carriage_return_found = False # Remove trailing '\r'. for linenum in range(len(lines)): if lines[linenum].endswith('\r'): lines[linenum] = lines[linenum].rstrip('\r') carriage_return_found = True except IOError: sys.stderr.write( "Skipping input '%s': Can't open for reading\n" % filename) return # Note, if no dot is found, this will give the entire filename as the ext. file_extension = filename[filename.rfind('.') + 1:] # When reading from stdin, the extension is unknown, so no cpplint tests # should rely on the extension. if (filename != '-' and file_extension != 'cc' and file_extension != 'h' and file_extension != 'cpp'): sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename) else: ProcessFileData(filename, file_extension, lines, Error, extra_check_functions) if carriage_return_found and os.linesep != '\r\n': # Use 0 for linenum since outputting only one error for potentially # several lines. Error(filename, 0, 'whitespace/newline', 1, 'One or more unexpected \\r (^M) found;' 'better to use only a \\n') #sys.stderr.write('Done processing %s\n' % filename) def PrintUsage(message): """Prints a brief usage string and exits, optionally with an error message. Args: message: The optional error message. """ sys.stderr.write(_USAGE) if message: sys.exit('\nFATAL ERROR: ' + message) else: sys.exit(1) def PrintCategories(): """Prints a list of all the error-categories used by error messages. These are the categories used to filter messages via --filter. """ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) sys.exit(0) def ParseArguments(args): """Parses the command line arguments. This may set the output format and verbosity level as side-effects. Args: args: The command line arguments: Returns: The list of filenames to lint. """ try: (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', 'counting=', 'filter=']) except getopt.GetoptError: PrintUsage('Invalid arguments.') verbosity = _VerboseLevel() output_format = _OutputFormat() filters = '' counting_style = '' for (opt, val) in opts: if opt == '--help': PrintUsage(None) elif opt == '--output': if not val in ('emacs', 'vs7'): PrintUsage('The only allowed output formats are emacs and vs7.') output_format = val elif opt == '--verbose': verbosity = int(val) elif opt == '--filter': filters = val if not filters: PrintCategories() elif opt == '--counting': if val not in ('total', 'toplevel', 'detailed'): PrintUsage('Valid counting options are total, toplevel, and detailed') counting_style = val if not filenames: PrintUsage('No files were specified.') _SetOutputFormat(output_format) _SetVerboseLevel(verbosity) _SetFilters(filters) _SetCountingStyle(counting_style) return filenames def main(): filenames = ParseArguments(sys.argv[1:]) # Change stderr to write with replacement characters so we don't die # if we try to print something containing non-ASCII characters. sys.stderr = codecs.StreamReaderWriter(sys.stderr, codecs.getreader('utf8'), codecs.getwriter('utf8'), 'replace') _cpplint_state.ResetErrorCounts() for filename in filenames: ProcessFile(filename, _cpplint_state.verbose_level) _cpplint_state.PrintErrorCounts() sys.exit(_cpplint_state.error_count > 0) if __name__ == '__main__': main() mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/docs.py000066400000000000000000000023251273231111400243440ustar00rootroot00000000000000"""Build the C++ client docs. """ from __future__ import with_statement import os import shutil import subprocess def clean_dir(dir): try: shutil.rmtree(dir) except: pass os.makedirs(dir) def gen_cplusplus(dir): clean_dir(dir) clean_dir("docs/doxygen") # Too noisy... with open("/dev/null") as null: subprocess.call(["doxygen", "etc/doxygen/config"], stdout=null, stderr=null) os.rename("docs/doxygen/html", dir) def version(): """Get the server version from doxygenConfig. """ with open("etc/doxygen/config") as f: for line in f.readlines(): if line.startswith("PROJECT_NUMBER"): return line.split("=")[1].strip() def link_current(version): """Create current link to the most recently generated documentation """ print("Updating 'current' docs symlink") link_path = 'docs/html/cplusplus/current' try: os.unlink(link_path) except OSError: pass os.symlink(version, link_path) def main(): v = version() print("Generating C++ docs in docs/html/cplusplus/%s" % v) gen_cplusplus("docs/html/cplusplus/%s" % v) link_current(v) if __name__ == "__main__": main() mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/git.py000066400000000000000000000022741273231111400242020ustar00rootroot00000000000000import os import re def getGitBranch(): if not os.path.exists( ".git" ) or not os.path.isdir(".git"): return None version = open( ".git/HEAD" ,'r' ).read().strip() if not version.startswith( "ref: " ): return version version = version.split( "/" ) version = version[len(version)-1] return version def getGitBranchString( prefix="" , postfix="" ): t = re.compile( '[/\\\]' ).split( os.getcwd() ) if len(t) > 2 and t[len(t)-1] == "mongo": par = t[len(t)-2] m = re.compile( ".*_([vV]\d+\.\d+)$" ).match( par ) if m is not None: return prefix + m.group(1).lower() + postfix if par.find("Nightly") > 0: return "" b = getGitBranch() if b == None or b == "master": return "" return prefix + b + postfix def getGitVersion(): if not os.path.exists( ".git" ) or not os.path.isdir(".git"): return "nogitversion" version = open( ".git/HEAD" ,'r' ).read().strip() if not version.startswith( "ref: " ): return version version = version[5:] f = ".git/" + version if not os.path.exists( f ): return version return open( f , 'r' ).read().strip() mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/lint.py000066400000000000000000000101311273231111400243540ustar00rootroot00000000000000 import sys import codecs import cpplint import utils def run_lint( paths, nudgeOn=False ): # errors are as of 10/14 # idea is not to let it any new type of error # as we knock one out, we should remove line # note: not all of these are things we want, so please check first nudge = [] # things we'd like to turn on sson, so don't make worse later = [] # things that are unlikely anytime soon, so meh never = [] # things we totally disagree with nudge.append( '-build/class' ) # errors found: 1 never.append( '-build/header_guard' ) # errors found: 345 nudge.append( '-build/include' ) # errors found: 924 nudge.append( '-build/include_order' ) # errors found: 511 nudge.append( '-build/include_what_you_use' ) # errors found: 986 nudge.append( '-build/namespaces' ) # errors found: 131 never.append( '-readability/braces' ) # errors found: 880 later.append( '-readability/casting' ) # errors found: 748 nudge.append( '-readability/function' ) # errors found: 49 later.append( '-readability/streams' ) # errors found: 72 later.append( '-readability/todo' ) # errors found: 309 nudge.append( '-runtime/arrays' ) # errors found: 5 nudge.append( '-runtime/casting' ) # errors found: 2 later.append( '-runtime/explicit' ) # errors found: 322 later.append( '-runtime/int' ) # errors found: 1420 later.append( '-runtime/printf' ) # errors found: 29 nudge.append( '-runtime/references' ) # errors found: 1338 nudge.append( '-runtime/rtti' ) # errors found: 36 nudge.append( '-runtime/sizeof' ) # errors found: 57 nudge.append( '-runtime/string' ) # errors found: 6 nudge.append( '-runtime/threadsafe_fn' ) # errors found: 46 never.append( '-whitespace/blank_line' ) # errors found: 2080 never.append( '-whitespace/braces' ) # errors found: 962 later.append( '-whitespace/comma' ) # errors found: 621 later.append( '-whitespace/comments' ) # errors found: 2189 later.append( '-whitespace/end_of_line' ) # errors found: 4340 later.append( '-whitespace/labels' ) # errors found: 58 later.append( '-whitespace/line_length' ) # errors found: 14500 later.append( '-whitespace/newline' ) # errors found: 1520 nudge.append( '-whitespace/operators' ) # errors found: 2297 never.append( '-whitespace/parens' ) # errors found: 49058 nudge.append( '-whitespace/semicolon' ) # errors found: 121 nudge.append( '-whitespace/tab' ) # errors found: 233 filters = later + never if not nudgeOn: filters = filters + nudge sourceFiles = [] for x in paths: utils.getAllSourceFiles( sourceFiles, x ) args = [ "--filter=" + ",".join( filters ) , "--counting=detailed" ] + sourceFiles filenames = cpplint.ParseArguments( args ) def _ourIsTestFilename(fn): if fn.find( "dbtests" ) >= 0: return True if fn.endswith( "_test.cpp" ): return True return False cpplint._IsTestFilename = _ourIsTestFilename # Change stderr to write with replacement characters so we don't die # if we try to print something containing non-ASCII characters. sys.stderr = codecs.StreamReaderWriter(sys.stderr, codecs.getreader('utf8'), codecs.getwriter('utf8'), 'replace') cpplint._cpplint_state.ResetErrorCounts() for filename in filenames: cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level) cpplint._cpplint_state.PrintErrorCounts() return cpplint._cpplint_state.error_count == 0 if __name__ == "__main__": paths = [] nudge = False for arg in sys.argv[1:]: if arg.startswith( "--" ): arg = arg[2:] if arg == "nudge": nudge = True continue else: print( "unknown arg [%s]" % arg ) sys.exit(-1) paths.append( arg ) if len(paths) == 0: paths.append( "src/mongo/" ) if not run_lint( paths, nudge ): sys.exit(-1) mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/resmokelib/000077500000000000000000000000001273231111400251745ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/resmokelib/__init__.py000066400000000000000000000000501273231111400273000ustar00rootroot00000000000000from __future__ import absolute_import mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/resmokelib/utils/000077500000000000000000000000001273231111400263345ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/resmokelib/utils/__init__.py000066400000000000000000000000501273231111400304400ustar00rootroot00000000000000from __future__ import absolute_import mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/resmokelib/utils/globstar.py000066400000000000000000000113751273231111400305320ustar00rootroot00000000000000""" Filename globbing utility. """ from __future__ import absolute_import import glob as _glob import os import os.path import re _GLOBSTAR = "**" _CONTAINS_GLOB_PATTERN = re.compile("[*?[]") def is_glob_pattern(s): """ Returns true if 's' represents a glob pattern, and false otherwise. """ # Copied from glob.has_magic(). return _CONTAINS_GLOB_PATTERN.search(s) is not None def glob(globbed_pathname): """ Return a list of pathnames matching the 'globbed_pathname' pattern. In addition to containing simple shell-style wildcards a la fnmatch, the pattern may also contain globstars ("**"), which is recursively expanded to match zero or more subdirectories. """ return list(iglob(globbed_pathname)) def iglob(globbed_pathname): """ Emit a list of pathnames matching the 'globbed_pathname' pattern. In addition to containing simple shell-style wildcards a la fnmatch, the pattern may also contain globstars ("**"), which is recursively expanded to match zero or more subdirectories. """ parts = _split_path(globbed_pathname) parts = _canonicalize(parts) index = _find_globstar(parts) if index == -1: for pathname in _glob.iglob(globbed_pathname): # Normalize 'pathname' so exact string comparison can be used later. yield os.path.normpath(pathname) return # **, **/, or **/a if index == 0: expand = _expand_curdir # a/** or a/**/ or a/**/b else: expand = _expand prefix_parts = parts[:index] suffix_parts = parts[index + 1:] prefix = os.path.join(*prefix_parts) if prefix_parts else os.curdir suffix = os.path.join(*suffix_parts) if suffix_parts else "" for (kind, path) in expand(prefix): if not suffix_parts: yield path # Avoid following symlinks to avoid an infinite loop elif suffix_parts and kind == "dir" and not os.path.islink(path): path = os.path.join(path, suffix) for pathname in iglob(path): yield pathname def _split_path(pathname): """ Return 'pathname' as a list of path components. """ parts = [] while True: (dirname, basename) = os.path.split(pathname) parts.append(basename) if pathname == dirname: parts.append(dirname) break if not dirname: break pathname = dirname parts.reverse() return parts def _canonicalize(parts): """ Return a copy of 'parts' with consecutive "**"s coalesced. Raise a ValueError for unsupported uses of "**". """ res = [] prev_was_globstar = False for p in parts: if p == _GLOBSTAR: # Skip consecutive **'s if not prev_was_globstar: prev_was_globstar = True res.append(p) elif _GLOBSTAR in p: # a/b**/c or a/**b/c raise ValueError("Can only specify glob patterns of the form a/**/b") else: prev_was_globstar = False res.append(p) return res def _find_globstar(parts): """ Return the index of the first occurrence of "**" in 'parts'. Return -1 if "**" is not found in the list. """ for (i, p) in enumerate(parts): if p == _GLOBSTAR: return i return -1 def _list_dir(pathname): """ Return a pair of the subdirectory names and filenames immediately contained within the 'pathname' directory. If 'pathname' does not exist, then None is returned. """ try: (_root, dirs, files) = os.walk(pathname).next() return (dirs, files) except StopIteration: return None # 'pathname' directory does not exist def _expand(pathname): """ Emit tuples of the form ("dir", dirname) and ("file", filename) of all directories and files contained within the 'pathname' directory. """ res = _list_dir(pathname) if res is None: return (dirs, files) = res # Zero expansion if os.path.basename(pathname): yield ("dir", os.path.join(pathname, "")) for f in files: path = os.path.join(pathname, f) yield ("file", path) for d in dirs: path = os.path.join(pathname, d) for x in _expand(path): yield x def _expand_curdir(pathname): """ Emit tuples of the form ("dir", dirname) and ("file", filename) of all directories and files contained within the 'pathname' directory. The returned pathnames omit a "./" prefix. """ res = _list_dir(pathname) if res is None: return (dirs, files) = res # Zero expansion yield ("dir", "") for f in files: yield ("file", f) for d in dirs: for x in _expand(d): yield x mongo-cxx-driver-legacy-1.1.2/site_scons/buildscripts/utils.py000066400000000000000000000035241273231111400245560ustar00rootroot00000000000000import os import re import subprocess import sys def getAllSourceFiles( arr=None , prefix="." ): if arr is None: arr = [] if not os.path.isdir( prefix ): # assume a file arr.append( prefix ) return arr for x in os.listdir( prefix ): if x.startswith( "." ) or x.startswith( "pcre-" ) or x.startswith( "32bit" ) or x.startswith( "mongodb-" ) or x.startswith("debian") or x.startswith( "mongo-cxx-driver" ): continue full = prefix + "/" + x if os.path.isdir( full ) and not os.path.islink( full ): getAllSourceFiles( arr , full ) else: if full.endswith( ".cpp" ) or full.endswith( ".h" ) or full.endswith( ".c" ): full = full.replace( "//" , "/" ) arr.append( full ) return arr # various utilities that are handy def find_python(min_version=(2, 5)): try: if sys.version_info >= min_version: return sys.executable except AttributeError: # In case the version of Python is somehow missing sys.version_info or sys.executable. pass version = re.compile(r'[Pp]ython ([\d\.]+)', re.MULTILINE) binaries = ('python27', 'python2.7', 'python26', 'python2.6', 'python25', 'python2.5', 'python') for binary in binaries: try: out, err = subprocess.Popen([binary, '-V'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() for stream in (out, err): match = version.search(stream) if match: versiontuple = tuple(map(int, match.group(1).split('.'))) if versiontuple >= min_version: return which(binary) except: pass raise Exception('could not find suitable Python (version >= %s)' % '.'.join(str(v) for v in min_version)) mongo-cxx-driver-legacy-1.1.2/site_scons/site_tools/000077500000000000000000000000001273231111400225155ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/site_scons/site_tools/integration_test.py000066400000000000000000000015471273231111400264600ustar00rootroot00000000000000"""Pseudo-builders for building and registering unit tests. """ def exists(env): return True def build_integration_test(env, target, source, **kwargs): result = env.Program(target, source, **kwargs) buildAlias = env.Alias('build-' + target, result) env.Alias('build-integration', buildAlias) env['ENV']['GTEST_FILTER'] = env.get("gtest_filter", "*") runAlias = env.Alias('run-' + target, [result], "%s %s:%s %s" % ( result[0].abspath, env.GetOption("mongo-orchestration-host"), env.GetOption("mongo-orchestration-port"), env.GetOption("mongo-orchestration-preset"))) env.AlwaysBuild(runAlias) testAliases = ['integration'] env.Alias(testAliases, runAlias) env.AlwaysBuild(testAliases) return result def generate(env): env.AddMethod(build_integration_test, 'IntegrationTest') mongo-cxx-driver-legacy-1.1.2/site_scons/site_tools/unittest.py000066400000000000000000000012051273231111400247440ustar00rootroot00000000000000"""Pseudo-builders for building and registering unit tests. """ def exists(env): return True def build_cpp_unit_test(env, target, source, **kwargs): result = env.Program(target, source, **kwargs) buildAlias = env.Alias('build-' + target, result) env.Alias('build-unit', buildAlias) env['ENV']['GTEST_FILTER'] = env.get("gtest_filter", "*") runAlias = env.Alias('run-' + target, [result], result[0].abspath) env.AlwaysBuild(runAlias) testAlias = 'unit' env.Alias(testAlias, runAlias) env.AlwaysBuild(testAlias) return result def generate(env): env.AddMethod(build_cpp_unit_test, 'CppUnitTest') mongo-cxx-driver-legacy-1.1.2/src/000077500000000000000000000000001273231111400167475ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/SConscript000066400000000000000000000004431273231111400207620ustar00rootroot00000000000000# -*- mode: python; -*- # # This is the principle SConscript file, invoked by the SConstruct. Its job is # to delegate to any and all per-module SConscript files. Import('env') env.SConscript('third_party/SConscript') env.SConscript('SConscript.client') env.SConscript('mongo/SConscript') mongo-cxx-driver-legacy-1.1.2/src/SConscript.client000066400000000000000000000565541273231111400222550ustar00rootroot00000000000000# -*- mode: python -*- # This SConscript describes build and install rules for the Mongo C++ driver and associated exmaple # programs. import buildscripts.git import httplib import json import os import re import time import urllib Import('env has_option get_option') Import('nix linux darwin windows') buildShared = False if has_option("sharedclient"): buildShared = True libEnv = env.Clone() libEnv.Append(CPPDEFINES=['LIBMONGOCLIENT_BUILDING']) # We want to build the same objects in two different ways, once for a static, and once for a # DLL, with different defines in play. That works fine on platforms where by default # SHOBJSUFFIX and OBJSUFFIX differ, but by default on windows they don't. Repair that. if windows: libEnv['SHOBJSUFFIX'] = libEnv['OBJSUFFIX'] + 's' clientEnv = env.Clone() clientEnv['CPPDEFINES'].remove('MONGO_EXPOSE_MACROS') # Prevent accidental usage of the unconfigured environment. del env libEnv.Command(['mongo/base/error_codes.h', 'mongo/base/error_codes.cpp',], ['mongo/base/generate_error_codes.py', 'mongo/base/error_codes.err'], '$PYTHON $SOURCES $TARGETS') def makeConfigHDefine(env, subst_key, env_var): replacement = "// #undef %s" value = env.get(env_var, None) if value: replacement = "#define %s 1" return (subst_key, replacement % env_var) libEnv.AddMethod(makeConfigHDefine) def makeConfigHDefineWithValue(env, subst_key, env_var): value = env.get(env_var) replacement = "#define %s %s" return (subst_key, replacement % (env_var, value)) libEnv.AddMethod(makeConfigHDefineWithValue) configSubstitutions = [ libEnv.makeConfigHDefine('@mongoclient_ssl@', 'MONGO_SSL'), libEnv.makeConfigHDefine('@mongoclient_sasl@', 'MONGO_SASL'), libEnv.makeConfigHDefine('@mongoclient_have_header_unistd_h@', 'MONGO_HAVE_HEADER_UNISTD_H'), libEnv.makeConfigHDefine('@mongoclient_have_cxx11_atomics@', 'MONGO_HAVE_CXX11_ATOMICS'), libEnv.makeConfigHDefine('@mongoclient_have_gcc_atomic_builtins@', 'MONGO_HAVE_GCC_ATOMIC_BUILTINS'), libEnv.makeConfigHDefine('@mongoclient_have_gcc_sync_builtins@', 'MONGO_HAVE_GCC_SYNC_BUILTINS'), libEnv.makeConfigHDefine('@mongoclient_have_std_is_trivially_copyable@', 'MONGO_HAVE_STD_IS_TRIVIALLY_COPYABLE'), libEnv.makeConfigHDefine('@mongoclient_have_strnlen@', 'MONGO_HAVE_STRNLEN'), libEnv.makeConfigHDefineWithValue('@mongoclient_byte_order@', 'MONGO_BYTE_ORDER'), ] libEnv.Substfile('mongo/config.h.in', SUBST_DICT=configSubstitutions) versionSubstitutions = [ ('@mongoclient_version@', libEnv['MONGOCLIENT_VERSION']), ('@mongoclient_version_major@', libEnv['MONGOCLIENT_VERSION_MAJOR']), ('@mongoclient_version_minor@', libEnv['MONGOCLIENT_VERSION_MINOR']), ('@mongoclient_version_patch@', libEnv['MONGOCLIENT_VERSION_PATCH']), ('@mongoclient_git_revision@', buildscripts.git.getGitVersion) ] libEnv.Substfile('mongo/version.h.in', SUBST_DICT=versionSubstitutions) clientSourceBasic = [ 'mongo/base/error_codes.cpp', 'mongo/base/global_initializer.cpp', 'mongo/base/global_initializer_registerer.cpp', 'mongo/base/init.cpp', 'mongo/base/initializer.cpp', 'mongo/base/initializer_context.cpp', 'mongo/base/initializer_dependency_graph.cpp', 'mongo/base/make_string_vector.cpp', 'mongo/base/parse_number.cpp', 'mongo/base/status.cpp', 'mongo/base/string_data.cpp', 'mongo/bson/bson_validate.cpp', 'mongo/bson/bsonelement.cpp', 'mongo/bson/bsonmisc.cpp', 'mongo/bson/bsonobj.cpp', 'mongo/bson/bsonobjbuilder.cpp', 'mongo/bson/bsonobjiterator.cpp', 'mongo/bson/bsontypes.cpp', 'mongo/bson/oid.cpp', 'mongo/bson/util/bson_extract.cpp', 'mongo/client/bulk_operation_builder.cpp', 'mongo/client/bulk_update_builder.cpp', 'mongo/client/bulk_upsert_builder.cpp', 'mongo/client/command_writer.cpp', 'mongo/client/dbclient.cpp', 'mongo/client/dbclient_rs.cpp', 'mongo/client/dbclientcursor.cpp', 'mongo/client/dbclientcursorshimarray.cpp', 'mongo/client/dbclientcursorshimcursorid.cpp', 'mongo/client/dbclientcursorshimtransform.cpp', 'mongo/client/delete_write_operation.cpp', 'mongo/client/exceptions.cpp', 'mongo/client/gridfs.cpp', 'mongo/client/index_spec.cpp', 'mongo/client/init.cpp', 'mongo/client/insert_write_operation.cpp', 'mongo/client/options.cpp', 'mongo/client/replica_set_monitor.cpp', 'mongo/client/sasl_client_authenticate.cpp', 'mongo/client/update_write_operation.cpp', 'mongo/client/wire_protocol_writer.cpp', 'mongo/client/write_concern.cpp', 'mongo/client/write_operation_base.cpp', 'mongo/client/write_result.cpp', 'mongo/db/dbmessage.cpp', 'mongo/db/json.cpp', 'mongo/geo/coordinates2d.cpp', 'mongo/geo/coordinates2dgeographic.cpp', 'mongo/logger/component_message_log_domain.cpp', 'mongo/logger/log_component.cpp', 'mongo/logger/log_component_settings.cpp', 'mongo/logger/log_manager.cpp', 'mongo/logger/log_severity.cpp', 'mongo/logger/logger.cpp', 'mongo/logger/logstream_builder.cpp', 'mongo/logger/message_event_utf8_encoder.cpp', 'mongo/logger/message_log_domain.cpp', 'mongo/platform/random.cpp', 'mongo/platform/strnlen.cpp', 'mongo/util/assert_util.cpp', 'mongo/util/background.cpp', 'mongo/util/base64.cpp', 'mongo/util/concurrency/synchronization.cpp', 'mongo/util/fail_point.cpp', 'mongo/util/fail_point_registry.cpp', 'mongo/util/fail_point_service.cpp', 'mongo/util/hex.cpp', 'mongo/util/log.cpp', 'mongo/util/md5.cpp', 'mongo/util/net/hostandport.cpp', 'mongo/util/net/message.cpp', 'mongo/util/net/message_port.cpp', 'mongo/util/net/sock.cpp', 'mongo/util/net/socket_poll.cpp', 'mongo/util/net/ssl_manager.cpp', 'mongo/util/password_digest.cpp', 'mongo/util/stringutils.cpp', 'mongo/util/text.cpp', 'mongo/util/time_support.cpp', 'mongo/util/timer.cpp', 'third_party/murmurhash3/MurmurHash3.cpp', ] # polyfills for platforms that don't have certain system provided functions clientSourceTz = [] if (clientEnv['MONGO_HAVE_TIMEGM'] or windows) else ['third_party/tz/timegm.c'] clientSourceSSL = [ 'mongo/client/native_sasl_client_session.cpp', 'mongo/client/sasl_client_authenticate_impl.cpp', 'mongo/client/sasl_client_conversation.cpp', 'mongo/client/sasl_client_session.cpp', 'mongo/client/sasl_plain_client_conversation.cpp', 'mongo/client/sasl_scramsha1_client_conversation.cpp', 'mongo/crypto/crypto_openssl.cpp', 'mongo/crypto/mechanism_scram.cpp', ] clientSourceSasl = [ 'mongo/client/cyrus_sasl_client_session.cpp', 'mongo/client/sasl_sspi.cpp', ] clientSource = clientSourceBasic + clientSourceTz usingSsl = libEnv['MONGO_SSL'] if usingSsl: clientSource += clientSourceSSL usingSasl = libEnv['MONGO_SASL'] if usingSasl: clientSource += clientSourceSasl exampleSourceMap = [ ('aggregation', 'mongo/client/examples/aggregation.cpp'), ('arrayExample', 'mongo/client/examples/arrayExample.cpp'), ('authTest', 'mongo/client/examples/authTest.cpp'), ('initializeTest', 'mongo/client/examples/initializeTest.cpp'), ('loggingTest', 'mongo/client/examples/loggingTest.cpp'), ('clientTest', 'mongo/client/examples/clientTest.cpp'), ('firstExample', 'mongo/client/examples/first.cpp'), ('geojsonExample', 'mongo/client/examples/geojson_demo.cpp'), ('insertDemo', 'mongo/client/examples/insert_demo.cpp'), ('rsExample', 'mongo/client/examples/rs.cpp'), ('secondExample', 'mongo/client/examples/second.cpp'), ('simpleClientDemo', 'mongo/client/examples/simple_client_demo.cpp'), ('tutorial', 'mongo/client/examples/tutorial.cpp'), ('whereExample', 'mongo/client/examples/whereExample.cpp'), ('bsondemo', 'mongo/bson/bsondemo/bsondemo.cpp'), ('connect', 'mongo/client/examples/connect.cpp'), ] clientHeaders = [ 'mongo/base/data_cursor.h', 'mongo/base/data_view.h', 'mongo/base/disallow_copying.h', 'mongo/base/encoded_value_storage.h', 'mongo/base/error_codes.h', 'mongo/base/parse_number.h', 'mongo/base/status-inl.h', 'mongo/base/status.h', 'mongo/base/status_with.h', 'mongo/base/string_data-inl.h', 'mongo/base/string_data.h', 'mongo/bson/bson-inl.h', 'mongo/bson/bson.h', 'mongo/bson/bson_db.h', 'mongo/bson/bson_field.h', 'mongo/bson/bson_validate.h', 'mongo/bson/bsonelement.h', 'mongo/bson/bsonmisc.h', 'mongo/bson/bsonobj.h', 'mongo/bson/bsonobjbuilder.h', 'mongo/bson/bsonobjiterator.h', 'mongo/bson/bsontypes.h', 'mongo/bson/inline_decls.h', 'mongo/bson/oid.h', 'mongo/bson/ordering.h', 'mongo/bson/timestamp.h', 'mongo/bson/util/builder.h', 'mongo/client/autolib.h', 'mongo/client/bulk_operation_builder.h', 'mongo/client/bulk_update_builder.h', 'mongo/client/bulk_upsert_builder.h', 'mongo/client/dbclient.h', 'mongo/client/dbclient_rs.h', 'mongo/client/dbclientcursor.h', 'mongo/client/dbclientinterface.h', 'mongo/client/exceptions.h', 'mongo/client/export_macros.h', 'mongo/client/gridfs.h', 'mongo/client/index_spec.h', 'mongo/client/init.h', 'mongo/client/options.h', 'mongo/client/redef_macros.h', 'mongo/client/sasl_client_authenticate.h', 'mongo/client/undef_macros.h', 'mongo/client/write_concern.h', 'mongo/client/write_options.h', 'mongo/client/write_result.h', 'mongo/config.h', 'mongo/db/jsobj.h', 'mongo/db/json.h', 'mongo/geo/boundingbox.h', 'mongo/geo/constants.h', 'mongo/geo/coordinates.h', 'mongo/geo/coordinates2d.h', 'mongo/geo/coordinates2dgeographic.h', 'mongo/geo/geometry.h', 'mongo/geo/geometrycollection.h', 'mongo/geo/geoobj.h', 'mongo/geo/interface.h', 'mongo/geo/linestring.h', 'mongo/geo/multilinestring.h', 'mongo/geo/multipoint.h', 'mongo/geo/multipolygon.h', 'mongo/geo/namespaces.h', 'mongo/geo/parser-impl.h', 'mongo/geo/parser.h', 'mongo/geo/point.h', 'mongo/geo/polygon.h', 'mongo/geo/queryutils.h', 'mongo/logger/appender.h', 'mongo/logger/component_message_log_domain.h', 'mongo/logger/labeled_level.h', 'mongo/logger/log_component.h', 'mongo/logger/log_component_settings.h', 'mongo/logger/log_domain.h', 'mongo/logger/log_manager.h', 'mongo/logger/log_severity-inl.h', 'mongo/logger/log_severity.h', 'mongo/logger/logger.h', 'mongo/logger/logstream_builder.h', 'mongo/logger/message_event.h', 'mongo/logger/message_log_domain.h', 'mongo/platform/atomic_intrinsics.h', 'mongo/platform/atomic_intrinsics_gcc_atomic.h', 'mongo/platform/atomic_intrinsics_gcc_intel.h', 'mongo/platform/atomic_intrinsics_gcc_sync.h', 'mongo/platform/atomic_intrinsics_win32.h', 'mongo/platform/atomic_word.h', 'mongo/platform/atomic_word_cxx11.h', 'mongo/platform/atomic_word_intrinsics.h', 'mongo/platform/compiler.h', 'mongo/platform/compiler_gcc.h', 'mongo/platform/compiler_msvc.h', 'mongo/platform/cstdint.h', 'mongo/platform/endian.h', 'mongo/platform/float_utils.h', 'mongo/platform/hash_namespace.h', 'mongo/platform/strnlen.h', 'mongo/platform/unordered_map.h', 'mongo/platform/windows_basic.h', 'mongo/stdx/functional.h', 'mongo/util/assert_util.h', 'mongo/util/mongoutils/str.h', 'mongo/util/net/hostandport.h', 'mongo/util/net/message.h', 'mongo/util/net/message_port.h', 'mongo/util/net/operation.h', 'mongo/util/net/sock.h', 'mongo/util/shared_buffer.h', 'mongo/util/time_support.h', 'mongo/version.h', ] mongoClientLibs = [] if usingSasl: mongoClientLibs += ["sasl2"] if windows: mongoClientLibs += ["secur32"] mongoClientPrefixInstalls = [] staticLibEnv = libEnv.Clone() staticLibEnv.AppendUnique( CPPDEFINES=['STATIC_LIBMONGOCLIENT'], LIBS=mongoClientLibs, ) sharedLibName = 'mongoclient' staticLibName = 'mongoclient' if windows: # On Windows, we need to have the static library target and the # import library target have different names, so that they aren't # ambiguous to scons. Boost names the static library libxxxx.lib and # the import library xxxx.lib, so we shall follow their lead. staticLibName = 'libmongoclient' abi_adornment=str() if not has_option('dynamic-windows'): abi_adornment += 's' if get_option('dbg') == 'on': abi_adornment += 'gd' if abi_adornment: abi_adornment = '-' + abi_adornment sharedLibName = sharedLibName + abi_adornment staticLibName = staticLibName + abi_adornment mongoClientStaticLib = staticLibEnv.StaticLibrary( staticLibName, clientSource), libEnv.Alias('driver', mongoClientStaticLib) mongoClientPrefixInstalls.append(libEnv.Install("$INSTALL_DIR/lib", mongoClientStaticLib)) # Other things like tests need to link against the static library (and the deps of that static # lib) so export it so it can be easily referenced. Export({'mongoClientStaticLibs' : [mongoClientStaticLib] + mongoClientLibs}) mongoClientSharedLib = None if buildShared: # TODO: When we are ready to set a SONAME for mongoclient, set SHLIBVERSION=x.y.z in this # environment to enable SCons versioned shared library support, and then change the two # 'Install' calls in this block to 'InstallVersionedLibrary'. SHLIBVERSION and # InstallVersionedLibrary support is only stable in SCons > 2.3.0, so if you add support # here, be sure to add an EnsuredSconsVersion here as well. sharedLibEnv = libEnv.Clone() sharedLibEnv.AppendUnique(LIBS=mongoClientLibs) if linux and not has_option('sanitize'): sharedLibEnv.AppendUnique(SHLINKFLAGS=["-Wl,--as-needed", "-Wl,-zdefs"]) # On non-windows systems, we want to match the behavior of DLLs and not export all symbols # from the dynamic shared library unless they have been explicitly been marked. if not windows: sharedLibEnv.AppendUnique(CCFLAGS="-fvisibility=hidden") sharedLibEnv.AppendUnique(SHLINKFLAGS="-fvisibility=hidden") mongoClientSharedLib = sharedLibEnv.SharedLibrary(sharedLibName, clientSource) libEnv.Alias('driver', mongoClientSharedLib) if darwin: # Set up the copy of the client library we will link targets against so that those # targets record the relative target directory as the install_name. sharedLibEnv.AddPostAction( mongoClientSharedLib, "install_name_tool -id @rpath/lib/%s %s" % ( mongoClientSharedLib[0], mongoClientSharedLib[0].abspath )) mongoClientSharedLibPrefixInstall = sharedLibEnv.Install( '$INSTALL_DIR/lib', mongoClientSharedLib) if darwin: sharedLibEnv.AddPostAction( mongoClientSharedLibPrefixInstall, "install_name_tool -id %s %s" % ( mongoClientSharedLibPrefixInstall[0], mongoClientSharedLibPrefixInstall[0] )) mongoClientPrefixInstalls.append(mongoClientSharedLibPrefixInstall) inst = libEnv.InstallAs(['$INSTALL_DIR/include/' + x for x in clientHeaders], clientHeaders) libEnv.AddPostAction(inst, Chmod('$TARGET', 0644)) mongoClientPrefixInstalls.append(inst); installAlias = libEnv.Alias('install', mongoClientPrefixInstalls) # Build some simple mainlines that include the dbclient.h and bson.h headers # with things set up to include from the installation directory. # Remove anything that says $VARIANT_DIR from the CPPPATH, except for things in third party, # so we have a source for boost, etc if we aren't getting them from the system. limit_cpppath=[p for p in libEnv['CPPPATH'] if not ('$VARIANT_DIR' in p and not 'third_party' in p)] # Create an environment where include files and libraries come from the installation directory. installationTestEnv = libEnv.Clone( CPPPATH=["$INSTALL_DIR/include"] + limit_cpppath, LIBPATH=["$INSTALL_DIR/lib"], CPPDEFINES=['STATIC_LIBMONGOCLIENT'], ) include_dbclienth_test_file = 'mongo/client/include_dbclienth_test.cpp' libEnv.Depends(include_dbclienth_test_file, installAlias) include_dbclienth_test = installationTestEnv.Object( target='include_dbclienth_test', source=[include_dbclienth_test_file]) libEnv.AlwaysBuild(include_dbclienth_test) libEnv.NoCache(include_dbclienth_test) include_bsonh_test_file = 'mongo/client/include_bsonh_test.cpp' libEnv.Depends(include_bsonh_test_file, installAlias) include_bsonh_test = installationTestEnv.Object( target='include_bsonh_test', source=[include_bsonh_test_file]) libEnv.AlwaysBuild(include_bsonh_test) libEnv.NoCache(include_bsonh_test) libEnv.Alias('check-install', [ include_dbclienth_test, include_bsonh_test, ]) staticClientEnv = clientEnv.Clone() # On windows, we rely on autolib linking, so need to set a search path to the root of the build # dir where the .lib will go. On others, we just add the library to libs. if windows: staticClientEnv.PrependUnique(LIBPATH=['$VARIANT_DIR']) else: staticClientEnv.PrependUnique(LIBS=[mongoClientStaticLib]) # Pull in the libs that the static client depends on. staticClientEnv.AppendUnique(LIBS=mongoClientLibs) staticClientEnv.AppendUnique(CPPDEFINES=['STATIC_LIBMONGOCLIENT']) # Build each statically linked client program staticClientPrograms = [ staticClientEnv.Program(target, source) for (target, source) in exampleSourceMap ] # For autolib'ing, we need this to create the dependency edge if windows: staticClientEnv.Depends(staticClientPrograms, mongoClientStaticLib) # Install path for the examples. On non-windows, do something reasonable to not pollute # $INSTALL_DIR/bin. On windows anything goes, drop the static libs in bin. staticClientProgramInstallDir = "$INSTALL_DIR/share/mongo-cxx-driver/examples/static" if windows: staticClientProgramInstallDir = "$INSTALL_DIR/bin/examples/static" staticClientProgramInstalls = staticClientEnv.Install( staticClientProgramInstallDir, staticClientPrograms) # Do the same for the shared library case, if we are doing that. sharedClientPrograms = [] sharedClientProgramInstalls = [] if buildShared: sharedClientEnv = clientEnv.Clone() # On windows, we rely on autolib linking, so add the variant directory (where the .lib will # land) to the search path. Otherwise, just link directly to the binary. if windows: sharedClientEnv.PrependUnique( LIBPATH=['$VARIANT_DIR'] ) else: sharedClientEnv.PrependUnique( LIBS=[mongoClientSharedLib], ) # Pretend that these files are shared object suffixed so they don't conflict with the objects # for the static library. sharedClientEnv['OBJSUFFIX'] = sharedClientEnv['OBJSUFFIX'] + 's' # For non-darwin 'nix, just set the RPATH that this program will use # when installed. Note that this must match up with the install directory # set below. if nix: if darwin: sharedClientEnv.PrependUnique( LINKFLAGS="-Wl,-rpath,@loader_path/../../..") else: sharedClientEnv.PrependUnique( LINKFLAGS="-Wl,-z,origin", RPATH=[sharedClientEnv.Literal("\\$$ORIGIN/../../../lib")]) sharedClientPrograms = [ sharedClientEnv.Program( "sharedclient/" + target, source) for (target, source) in exampleSourceMap] # Note that this dependency also ensures the correct dependency edge in autolib cases. libEnv.Depends(sharedClientPrograms, mongoClientSharedLib) # For normal systems with runpaths, install the examples somewhere sane. Otherwise on # windows, drop them in the lib directory because there really isn't anywher else they can # live where they can find the DLL. sharedClientProgramInstallDir = "$INSTALL_DIR/share/mongo-cxx-driver/examples" if windows: sharedClientProgramInstallDir = "$INSTALL_DIR/lib" sharedClientProgramInstalls = sharedClientEnv.Install( sharedClientProgramInstallDir, sharedClientPrograms) sharedClientEnv.Depends(sharedClientProgramInstalls, mongoClientSharedLibPrefixInstall) clientTestPrograms = staticClientPrograms + sharedClientPrograms clientEnv.Alias('build-examples', clientTestPrograms) clientTestProgramInstalls = staticClientProgramInstalls + sharedClientProgramInstalls mongoDBUri = str() def getMongoDBUri(): return mongoDBUri clientEnv['getMongoDBUri'] = getMongoDBUri def setupMongoOrchestration(target, source, env): orchestration_uri = "%s:%s" % (env.GetOption("mongo-orchestration-host"), env.GetOption("mongo-orchestration-port")) json_headers = { "Content-Type": "application/json" } params = json.dumps({ "id": "standalone", "name": "mongod", "preset": env.GetOption("mongo-orchestration-preset") }) # Check if a standalone mongod is already up, resetting if it is MO_MAX_RETRIES = 10 for attempt in range(1, MO_MAX_RETRIES+1): if attempt > 1: # don't sleep before first attempt time.sleep(1) try: conn = httplib.HTTPConnection(orchestration_uri, timeout=30) conn.request("GET", "/servers/standalone", headers=json_headers) response = conn.getresponse() message = response.read() except IOError: print("Cannot connect to Mongo Orchestration at %s on attempt %d. %d attempts remaining..." % (orchestration_uri, attempt, MO_MAX_RETRIES - (attempt))) continue if (response.status == 404): print("No standalone started, starting one now...") post_conn = httplib.HTTPConnection(orchestration_uri, timeout=30) post_conn.request("POST", "/servers", params, json_headers) continue elif (response.status/100 != 2): print("Mongo Orchestration had an error with code %s" % response.status) if message: print("\tmessage from MO: %s", message) continue # Grab the port from the response -- use it in the tests decoded_response = json.loads(message) global mongoDBUri mongoDBUri = decoded_response['mongodb_uri'] # The last attempt succeeded so we don't need to keep trying break clientEnv.Alias('setup-mongo-orchestration', clientEnv.Command( target="#setup-mongo-orchestration", source=[], action=clientEnv.Action( setupMongoOrchestration, cmdstr="Configuring MongoOrchestration for Examples") )) for clientTest in clientTestProgramInstalls: # On windows, the installs also install PDB files, which we end up picking up. # Obviously, we can't run those, so filter them out. Lets hope nobody creates # a new client test with pdb in the name. if clientTest.abspath.endswith('.pdb'): continue # the rsExample test needs a replica set to talk to. The old smokeClient never tested it # The old smoke subsystem did test authTest, not sure why it isn't working now. if 'rsExample' in clientTest.abspath: continue command = clientEnv.Command( target="${SOURCE}-run", source=[clientTest], action="$SOURCE ${getMongoDBUri()}") clientEnv.SideEffect("#example-running", command) clientEnv.AlwaysBuild(command) clientEnv.Depends(command, 'setup-mongo-orchestration') clientEnv.Alias('examples', command) clientEnv.Alias('install-examples', clientTestProgramInstalls) mongo-cxx-driver-legacy-1.1.2/src/mongo/000077500000000000000000000000001273231111400200665ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/.clang-format000066400000000000000000000036131273231111400224440ustar00rootroot00000000000000# BasedOnStyle: Google AccessModifierOffset: -4 AlignOperands: false AlignAfterOpenBracket: true AlignEscapedNewlinesLeft: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: false AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false ColumnLimit: 100 CommentPragmas: '' ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IndentCaseLabels: true IndentFunctionDeclarationAfterType: false IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false Language: Cpp MaxEmptyLinesToKeep: 2 NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: true SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 4 UseTab: Never mongo-cxx-driver-legacy-1.1.2/src/mongo/SConscript000066400000000000000000000071341273231111400221050ustar00rootroot00000000000000Import('env windows mongoClientStaticLibs libGTestStatic') testEnv = env.Clone() conf = Configure(testEnv) conf.CheckLibWithHeader('curl', 'curl/curl.h', 'c') testEnv = conf.Finish() staticClientEnv = testEnv.Clone() staticClientEnv.PrependUnique( CPPDEFINES=[ 'STATIC_LIBMONGOCLIENT' ], LIBS=mongoClientStaticLibs, ) libMock = staticClientEnv.StaticLibrary( target='mocklib', source=[ "dbtests/mock/mock_conn_registry.cpp", "dbtests/mock/mock_dbclient_connection.cpp", "dbtests/mock/mock_dbclient_cursor.cpp", "dbtests/mock/mock_remote_db_server.cpp", "dbtests/mock/mock_replica_set.cpp", ], ) libUnitTestMain = staticClientEnv.StaticLibrary( target='unit_test_main', source=[ 'unittest/unit_test_main.cpp' ], ) libIntegrationTestMain = staticClientEnv.StaticLibrary( target='integration_test_main', source=[ '../third_party/restclient/restclient.cpp', '../third_party/jsoncpp/jsoncpp.cpp', 'orchestration/resource.cpp', 'orchestration/mongo_resource.cpp', 'orchestration/server.cpp', 'orchestration/service.cpp', 'orchestration/replica_set.cpp', 'orchestration/sharded_cluster.cpp', 'integration/integration_test_main.cpp' ], ) unittests = [ 'base/data_cursor_test', 'base/data_view_test', 'base/encoded_value_storage_test', 'base/parse_number_test', 'bson/bson_field_test', 'bson/bson_obj_test', 'bson/bson_validate_test', 'bson/bsonobjbuilder_test', 'bson/oid_test', 'bson/util/bson_extract_test', 'bson/util/builder_test', 'client/connection_string_test', 'client/dbclient_rs_test', 'client/index_spec_test', 'client/insert_write_operation_test', 'client/replica_set_monitor_test', 'client/write_concern_test', 'db/dbmessage_test', 'db/namespace_string_test', 'dbtests/jsobjtests', 'dbtests/jsontests', 'dbtests/mock_dbclient_conn_test', 'dbtests/mock_replica_set_test', 'dbtests/replica_set_monitor_test', 'geo/geo_test', 'logger/log_test', 'platform/atomic_word_test', 'platform/endian_test', 'platform/random_test', 'unittest/connection_string_test', 'unittest/query_test', 'util/mongoutils/str_test', 'util/net/hostandport_test', 'util/net/sock_test', 'util/string_map_test', 'util/stringutils_test', 'util/time_support_test', ] if env['MONGO_SSL']: unittests += ['crypto/crypto_test'] gtestEnv = staticClientEnv.Clone() gtestEnv.PrependUnique( # On windows, we need this odd flag to make the linker # search for main in our _test_main libs. LINKFLAGS=(['/SUBSYSTEM:CONSOLE'] if windows else []), LIBS=[ libGTestStatic, ]) unitTestEnv = gtestEnv.Clone() unitTestEnv.PrependUnique( LIBS=[ libUnitTestMain, libMock, ]) for unittest in unittests: unitTestEnv.CppUnitTest( target=unittest, source=[ unittest + '.cpp' ]) integration_tests = [ 'standalone/bulk_operation_test', 'standalone/dbclient_test', 'standalone/dbclient_writer_test', 'standalone/gridfs_test', 'replica_set/basic', 'replica_set/read_preference' ] if env['MONGO_SASL']: integration_tests += ['standalone/sasl_test'] integrationTestEnv = gtestEnv.Clone() integrationTestEnv.PrependUnique( LIBS=[ libIntegrationTestMain ]) for integration_test in integration_tests: integrationTestEnv.IntegrationTest( target=integration_test, source=[ 'integration/' + integration_test + '.cpp' ] ) mongo-cxx-driver-legacy-1.1.2/src/mongo/base/000077500000000000000000000000001273231111400210005ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/base/compare_numbers.h000066400000000000000000000061071273231111400243360ustar00rootroot00000000000000/* Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/platform/float_utils.h" namespace mongo { /** * These functions compare numbers using the same rules as BSON. Care is taken to always give * numerically correct results when comparing different types. Returns are always -1, 0, or 1 to * ensure it is safe to negate the result to invert the direction of the comparison. */ inline int compareInts(int lhs, int rhs) { return lhs == rhs ? 0 : lhs < rhs ? -1 : 1; } inline int compareLongs(long long lhs, long long rhs) { return lhs == rhs ? 0 : lhs < rhs ? -1 : 1; } inline int compareDoubles(double lhs, double rhs) { if (lhs == rhs) return 0; if (lhs < rhs) return -1; if (lhs > rhs) return 1; // If none of the above cases returned, lhs or rhs must be NaN. if (isNaN(lhs)) return isNaN(rhs) ? 0 : -1; return 1; } // This is the tricky one. Needs to support the following cases: // * Doubles with a fractional component. // * Longs that can't be precisely represented as a double. // * Doubles outside of the range of Longs (including +/- Inf). // * NaN (defined by us as less than all Longs) // * Return value is always -1, 0, or 1 to ensure it is safe to negate. inline int compareLongToDouble(long long lhs, double rhs) { // All Longs are > NaN if (isNaN(rhs)) return 1; // Ints with magnitude <= 2**53 can be precisely represented as doubles. // Additionally, doubles outside of this range can't have a fractional component. static const long long kEndOfPreciseDoubles = 1ll << 53; if (lhs <= kEndOfPreciseDoubles && lhs >= -kEndOfPreciseDoubles) { return compareDoubles(lhs, rhs); } // Large magnitude doubles (including +/- Inf) are strictly > or < all Longs. static const double kBoundOfLongRange = -static_cast(LLONG_MIN); // positive 2**63 if (rhs >= kBoundOfLongRange) return -1; // Can't be represented in a Long. if (rhs < -kBoundOfLongRange) return 1; // Can be represented in a Long. // Remaining Doubles can have their integer component precisely represented as long longs. // If they have a fractional component, they must be strictly > or < lhs even after // truncation of the fractional component since low-magnitude lhs were handled above. return compareLongs(lhs, rhs); } inline int compareDoubleToLong(double lhs, long long rhs) { // Only implement the real logic once. return -compareLongToDouble(rhs, lhs); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/data_cursor.h000066400000000000000000000105321273231111400234600ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/data_view.h" #include "mongo/platform/endian.h" namespace mongo { class ConstDataCursor : public ConstDataView { public: typedef ConstDataView view_type; ConstDataCursor(ConstDataView::bytes_type bytes) : ConstDataView(bytes) {} ConstDataCursor operator+(std::size_t s) const { return view() + s; } ConstDataCursor& operator+=(std::size_t s) { *this = view() + s; return *this; } ConstDataCursor operator-(std::size_t s) const { return view() - s; } ConstDataCursor& operator-=(std::size_t s) { *this = view() - s; return *this; } ConstDataCursor& operator++() { return operator+=(1); } ConstDataCursor operator++(int) { ConstDataCursor tmp = *this; operator++(); return tmp; } ConstDataCursor& operator--() { return operator-=(1); } ConstDataCursor operator--(int) { ConstDataCursor tmp = *this; operator--(); return tmp; } template ConstDataCursor& skip() { *this = view() + sizeof(T); return *this; } template ConstDataCursor& readNativeAndAdvance(T* t) { readNative(t); skip(); return *this; } template T readNativeAndAdvance() { T out; readNativeAndAdvance(&out); return out; } template T readLEAndAdvance() { return endian::littleToNative(readNativeAndAdvance()); } template T readBEAndAdvance() { return endian::bigToNative(readNativeAndAdvance()); } }; class DataCursor : public DataView { public: typedef DataView view_type; DataCursor(DataView::bytes_type bytes) : DataView(bytes) {} operator ConstDataCursor() const { return view(); } DataCursor operator+(std::size_t s) const { return view() + s; } DataCursor& operator+=(std::size_t s) { *this = view() + s; return *this; } DataCursor operator-(std::size_t s) const { return view() - s; } DataCursor& operator-=(std::size_t s) { *this = view() - s; return *this; } DataCursor& operator++() { return operator+=(1); } DataCursor operator++(int) { DataCursor tmp = *this; operator++(); return tmp; } DataCursor& operator--() { return operator-=(1); } DataCursor operator--(int) { DataCursor tmp = *this; operator--(); return tmp; } template DataCursor& skip() { *this = view() + sizeof(T); return *this; } template DataCursor& readNativeAndAdvance(T* t) { readNative(t); skip(); return *this; } template T readNativeAndAdvance() { T out; readNativeAndAdvance(&out); return out; } template T readLEAndAdvance() { return endian::littleToNative(readNativeAndAdvance()); } template T readBEAndAdvance() { return endian::bigToNative(readNativeAndAdvance()); } template DataCursor& writeNativeAndAdvance(const T& value) { writeNative(value); skip(); return *this; } template DataCursor& writeLEAndAdvance(const T& value) { return writeNativeAndAdvance(endian::nativeToLittle(value)); } template DataCursor& writeBEAndAdvance(const T& value) { return writeNativeAndAdvance(endian::nativeToBig(value)); } }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/data_cursor_test.cpp000066400000000000000000000054351273231111400250600ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/data_cursor.h" #include "mongo/platform/endian.h" #include "mongo/unittest/unittest.h" namespace mongo { TEST(DataCursor, ConstDataCursor) { char buf[100]; DataView(buf).writeNative(1); DataView(buf).writeLE(2, sizeof(uint16_t)); DataView(buf).writeBE(3, sizeof(uint16_t) + sizeof(uint32_t)); ConstDataCursor cdc(buf); ASSERT_EQUALS(static_cast(1), cdc.readNativeAndAdvance()); ASSERT_EQUALS(static_cast(2), cdc.readLEAndAdvance()); ASSERT_EQUALS(static_cast(3), cdc.readBEAndAdvance()); // test skip() cdc = buf; cdc.skip(); ASSERT_EQUALS(buf + sizeof(uint32_t), cdc.view()); // test x + cdc = buf; ASSERT_EQUALS(buf + sizeof(uint32_t), (cdc + sizeof(uint32_t)).view()); // test x - cdc = buf + sizeof(uint32_t); ASSERT_EQUALS(buf, (cdc - sizeof(uint32_t)).view()); // test x += and x -= cdc = buf; cdc += sizeof(uint32_t); ASSERT_EQUALS(buf + sizeof(uint32_t), cdc.view()); cdc -= sizeof(uint16_t); ASSERT_EQUALS(buf + sizeof(uint16_t), cdc.view()); // test ++x cdc = buf; ASSERT_EQUALS(buf + sizeof(uint8_t), (++cdc).view()); ASSERT_EQUALS(buf + sizeof(uint8_t), cdc.view()); // test x++ cdc = buf; ASSERT_EQUALS(buf, (cdc++).view()); ASSERT_EQUALS(buf + sizeof(uint8_t), cdc.view()); // test --x cdc = buf + sizeof(uint8_t); ASSERT_EQUALS(buf, (--cdc).view()); ASSERT_EQUALS(buf, cdc.view()); // test x-- cdc = buf + sizeof(uint8_t); ASSERT_EQUALS(buf + sizeof(uint8_t), (cdc--).view()); ASSERT_EQUALS(buf, cdc.view()); } TEST(DataCursor, DataCursor) { char buf[100]; DataCursor dc(buf); dc.writeNativeAndAdvance(1); dc.writeLEAndAdvance(2); dc.writeBEAndAdvance(3); ConstDataCursor cdc(buf); ASSERT_EQUALS(static_cast(1), cdc.readNativeAndAdvance()); ASSERT_EQUALS(static_cast(2), cdc.readLEAndAdvance()); ASSERT_EQUALS(static_cast(3), cdc.readBEAndAdvance()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/data_view.h000066400000000000000000000056321273231111400231220ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #include #include "mongo/platform/endian.h" #if __cplusplus >= 201103L #include #endif namespace mongo { class ConstDataView { public: typedef const char* bytes_type; ConstDataView(bytes_type bytes) : _bytes(bytes) {} bytes_type view(std::size_t offset = 0) const { return _bytes + offset; } template const ConstDataView& readNative(T* t, size_t offset = 0) const { #if MONGO_HAVE_STD_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, "Type for DataView::readNative must be trivially copyable"); #endif std::memcpy(t, view(offset), sizeof(*t)); return *this; } template T readNative(std::size_t offset = 0) const { T t; readNative(&t, offset); return t; } template T readLE(std::size_t offset = 0) const { return endian::littleToNative(readNative(offset)); } template T readBE(std::size_t offset = 0) const { return endian::bigToNative(readNative(offset)); } private: bytes_type _bytes; }; class DataView : public ConstDataView { public: typedef char* bytes_type; DataView(bytes_type bytes) : ConstDataView(bytes) {} bytes_type view(std::size_t offset = 0) const { // It is safe to cast away const here since the pointer stored in our base class was // originally non-const by way of our constructor. return const_cast(ConstDataView::view(offset)); } template DataView& writeNative(const T& value, std::size_t offset = 0) { #if MONGO_HAVE_STD_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, "Type for DataView::writeNative must be trivially copyable"); #endif std::memcpy(view(offset), &value, sizeof(value)); return *this; } template DataView& writeLE(const T& value, std::size_t offset = 0) { return writeNative(endian::nativeToLittle(value), offset); } template DataView& writeBE(const T& value, std::size_t offset = 0) { return writeNative(endian::nativeToBig(value), offset); } }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/data_view_test.cpp000066400000000000000000000036711273231111400245150ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/data_view.h" #include #include "mongo/platform/endian.h" #include "mongo/unittest/unittest.h" namespace mongo { TEST(DataView, ConstDataView) { char buf[sizeof(uint32_t) * 3]; uint32_t native = 1234; uint32_t le = endian::nativeToLittle(native); uint32_t be = endian::nativeToBig(native); std::memcpy(buf, &native, sizeof(uint32_t)); std::memcpy(buf + sizeof(uint32_t), &le, sizeof(uint32_t)); std::memcpy(buf + sizeof(uint32_t) * 2, &be, sizeof(uint32_t)); ConstDataView cdv(buf); ASSERT_EQUALS(buf, cdv.view()); ASSERT_EQUALS(buf + 5, cdv.view(5)); ASSERT_EQUALS(native, cdv.readNative()); ASSERT_EQUALS(native, cdv.readLE(sizeof(uint32_t))); ASSERT_EQUALS(native, cdv.readBE(sizeof(uint32_t) * 2)); } TEST(DataView, DataView) { char buf[sizeof(uint32_t) * 3]; uint32_t native = 1234; DataView dv(buf); dv.writeNative(native); dv.writeLE(native, sizeof(uint32_t)); dv.writeBE(native, sizeof(uint32_t) * 2); ASSERT_EQUALS(buf, dv.view()); ASSERT_EQUALS(buf + 5, dv.view(5)); ASSERT_EQUALS(native, dv.readNative()); ASSERT_EQUALS(native, dv.readLE(sizeof(uint32_t))); ASSERT_EQUALS(native, dv.readBE(sizeof(uint32_t) * 2)); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/disallow_copying.h000066400000000000000000000021321273231111400245150ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once /** * Instruct the compiler not to create default copy constructor and assignment operator * for class "CLASS". Must be the _first_ or _last_ line of the class declaration. Prefer * to use it as the first line. * * Usage: * class Foo { * MONGO_DISALLOW_COPYING(Foo); * public: * ... * }; */ #define MONGO_DISALLOW_COPYING(CLASS) \ private: \ CLASS(const CLASS&); \ CLASS& operator=(const CLASS&) mongo-cxx-driver-legacy-1.1.2/src/mongo/base/encoded_value_storage.h000066400000000000000000000037241273231111400255000ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/data_view.h" namespace mongo { struct ZeroInitTag_t { ZeroInitTag_t(){}; }; const ZeroInitTag_t kZeroInitTag; template class EncodedValueStorage { protected: EncodedValueStorage() {} // This explicit constructor is provided to allow for easy zeroing // during creation of a value. You might prefer this over an // uninitialised value if the zeroed version provides a useful base // state. Such cases might include a set of counters that begin at // zero, flags that start off false or a larger structure where some // significant portion of storage falls into those kind of use cases. // Use this where you might have used calloc(1, sizeof(type)) in C. // // The added value of providing it as a constructor lies in the ability // of subclasses to easily inherit a zeroed base state during // initialization. explicit EncodedValueStorage(ZeroInitTag_t) { std::memset(_data, 0, sizeof(_data)); } public: View view() { return _data; } ConstView constView() const { return _data; } operator View() { return view(); } operator ConstView() const { return constView(); } private: char _data[sizeof(Layout)]; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/encoded_value_storage_test.cpp000066400000000000000000000065761273231111400271020ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/encoded_value_storage.h" #include #include "mongo/platform/endian.h" #include "mongo/unittest/unittest.h" namespace mongo { // Simplistic encoded value view and value classes to test EncodedValueStorage namespace EncodedValueStorageTest { #pragma pack(1) struct Layout { uint32_t native; uint32_t le; uint32_t be; }; #pragma pack() class ConstView { public: typedef ConstDataView view_type; ConstView(const char* data) : _data(data) {} const char* view2ptr() const { return data().view(); } uint32_t getNative() { return data().readNative(offsetof(Layout, native)); } uint32_t getLE() { return data().readLE(offsetof(Layout, le)); } uint32_t getBE() { return data().readBE(offsetof(Layout, be)); } protected: const view_type& data() const { return _data; } private: view_type _data; }; class View : public ConstView { public: typedef DataView view_type; View(char* data) : ConstView(data) {} using ConstView::view2ptr; char* view2ptr() { return data().view(); } void setNative(uint32_t value) { data().writeNative(value, offsetof(Layout, native)); } void setLE(uint32_t value) { data().writeLE(value, offsetof(Layout, le)); } void setBE(uint32_t value) { data().writeBE(value, offsetof(Layout, be)); } private: view_type data() const { return const_cast(ConstView::view2ptr()); } }; class Value : public EncodedValueStorage { public: Value() { BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout)); } Value(ZeroInitTag_t zit) : EncodedValueStorage(zit) {} }; } TEST(EncodedValueStorage, EncodedValueStorage) { EncodedValueStorageTest::Value raw; EncodedValueStorageTest::Value zerod(kZeroInitTag); char buf[sizeof(EncodedValueStorageTest::Layout)] = {0}; ASSERT_EQUALS(raw.view().view2ptr(), raw.constView().view2ptr()); // ensure zeroing with the init tag works ASSERT_EQUALS(std::memcmp(zerod.view().view2ptr(), buf, sizeof(buf)), 0); // see if value assignment and view() works zerod.view().setNative(1234); EncodedValueStorageTest::View(buf).setNative(1234); raw = zerod; ASSERT_EQUALS(std::memcmp(raw.view().view2ptr(), buf, sizeof(buf)), 0); // see if view() and constView() work appropriately raw.view().setNative(1); raw.view().setLE(2); raw.view().setBE(3); ASSERT_EQUALS(static_cast(1), raw.constView().getNative()); ASSERT_EQUALS(static_cast(2), raw.constView().getLE()); ASSERT_EQUALS(static_cast(3), raw.constView().getBE()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/error_codes.err000066400000000000000000000123011273231111400240150ustar00rootroot00000000000000# -*- mode: python -*- error_code("OK", 0) error_code("InternalError", 1) error_code("BadValue", 2) error_code("OBSOLETE_DuplicateKey", 3) error_code("NoSuchKey", 4) error_code("GraphContainsCycle", 5) error_code("HostUnreachable", 6) error_code("HostNotFound", 7) error_code("UnknownError", 8) error_code("FailedToParse", 9) error_code("CannotMutateObject", 10) error_code("UserNotFound", 11) error_code("UnsupportedFormat", 12) error_code("Unauthorized", 13) error_code("TypeMismatch", 14) error_code("Overflow", 15) error_code("InvalidLength", 16) error_code("ProtocolError", 17) error_code("AuthenticationFailed", 18) error_code("CannotReuseObject", 19) error_code("IllegalOperation", 20) error_code("EmptyArrayOperation", 21) error_code("InvalidBSON", 22) error_code("AlreadyInitialized", 23) error_code("LockTimeout", 24) error_code("RemoteValidationError", 25) error_code("NamespaceNotFound", 26) error_code("IndexNotFound", 27) error_code("PathNotViable", 28) error_code("NonExistentPath", 29) error_code("InvalidPath", 30) error_code("RoleNotFound", 31) error_code("RolesNotRelated", 32) error_code("PrivilegeNotFound", 33) error_code("CannotBackfillArray", 34) error_code("UserModificationFailed", 35) error_code("RemoteChangeDetected", 36) error_code("FileRenameFailed", 37) error_code("FileNotOpen", 38) error_code("FileStreamFailed", 39) error_code("ConflictingUpdateOperators", 40) error_code("FileAlreadyOpen", 41) error_code("LogWriteFailed", 42) error_code("CursorNotFound", 43) error_code("UserDataInconsistent", 45) error_code("LockBusy", 46) error_code("NoMatchingDocument", 47) error_code("NamespaceExists", 48) error_code("InvalidRoleModification", 49) error_code("ExceededTimeLimit", 50) error_code("ManualInterventionRequired", 51) error_code("DollarPrefixedFieldName", 52) error_code("InvalidIdField", 53) error_code("NotSingleValueField", 54) error_code("InvalidDBRef", 55) error_code("EmptyFieldName", 56) error_code("DottedFieldName", 57) error_code("RoleModificationFailed", 58) error_code("CommandNotFound", 59) error_code("DatabaseNotFound", 60) error_code("ShardKeyNotFound", 61) error_code("OplogOperationUnsupported", 62) error_code("StaleShardVersion", 63) error_code("WriteConcernFailed", 64) error_code("MultipleErrorsOccurred", 65) error_code("ImmutableField", 66) error_code("CannotCreateIndex", 67 ) error_code("IndexAlreadyExists", 68 ) error_code("AuthSchemaIncompatible", 69) error_code("ShardNotFound", 70) error_code("ReplicaSetNotFound", 71) error_code("InvalidOptions", 72) error_code("InvalidNamespace", 73) error_code("NodeNotFound", 74) error_code("WriteConcernLegacyOK", 75) error_code("NoReplicationEnabled", 76) error_code("OperationIncomplete", 77) error_code("CommandResultSchemaViolation", 78) error_code("UnknownReplWriteConcern", 79) error_code("RoleDataInconsistent", 80) error_code("NoWhereParseContext", 81) error_code("NoProgressMade", 82) error_code("RemoteResultsUnavailable", 83) error_code("DuplicateKeyValue", 84) error_code("IndexOptionsConflict", 85 ) error_code("IndexKeySpecsConflict", 86 ) error_code("CannotSplit", 87) error_code("SplitFailed", 88) error_code("NetworkTimeout", 89) error_code("CallbackCanceled", 90) error_code("ShutdownInProgress", 91) error_code("SecondaryAheadOfPrimary", 92) error_code("InvalidReplicaSetConfig", 93) error_code("NotYetInitialized", 94) error_code("NotSecondary", 95) error_code("OperationFailed", 96) error_code("NoProjectionFound", 97) error_code("DBPathInUse", 98) error_code("WriteConcernNotDefined", 99) error_code("CannotSatisfyWriteConcern", 100) error_code("OutdatedClient", 101) error_code("IncompatibleAuditMetadata", 102) error_code("NewReplicaSetConfigurationIncompatible", 103) error_code("NodeNotElectable", 104) error_code("IncompatibleShardingMetadata", 105) error_code("DistributedClockSkewed", 106) error_code("LockFailed", 107) error_code("InconsistentReplicaSetNames", 108) error_code("ConfigurationInProgress", 109) error_code("CannotInitializeNodeWithData", 110) error_code("NotExactValueField", 111) error_code("WriteConflict", 112) error_code("InitialSyncFailure", 113) error_code("InitialSyncOplogSourceMissing", 114) error_code("CommandNotSupported", 115) error_code("DocTooLargeForCapped", 116) error_code("ConflictingOperationInProgress", 117) error_code("FailedToSatisfyReadPreference", 133) # backported error_code("OplogStartMissing", 120) error_code("CappedPositionLost", 121) # Non-sequential error codes (for compatibility only) error_code("NotMaster", 10107) #this comes from assert_util.h error_code("DuplicateKey", 11000) error_code("InterruptedAtShutdown", 11600) error_code("Interrupted", 11601) error_code("OutOfDiskSpace", 14031 ) error_code("KeyTooLong", 17280); error_code("BackgroundOperationInProgressForDatabase", 12586); error_code("BackgroundOperationInProgressForNamespace", 12587); error_code("NotMasterOrSecondaryCode", 13436); error_code("NotMasterNoSlaveOkCode", 13435); error_code("ShardKeyTooBig", 13334); error_class("NetworkError", ["HostUnreachable", "HostNotFound", "NetworkTimeout"]) error_class("Interruption", ["Interrupted", "InterruptedAtShutdown", "ExceededTimeLimit"]) error_class("IndexCreationError", ["CannotCreateIndex", "IndexOptionsConflict", "IndexKeySpecsConflict", "IndexAlreadyExists"]) mongo-cxx-driver-legacy-1.1.2/src/mongo/base/generate_error_codes.py000066400000000000000000000214401273231111400255330ustar00rootroot00000000000000#!/usr/bin/python # Copyright 2012 10gen Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # """Generate error_codes.{h,cpp} from error_codes.err. Format of error_codes.err: error_code("symbol1", code1) error_code("symbol2", code2) ... error_class("class1", ["symbol1", "symbol2, ..."]) Usage: python generate_error_codes.py
""" import sys def main(argv): if len(argv) != 4: usage("Wrong number of arguments.") error_codes, error_classes = parse_error_definitions_from_file(argv[1]) check_for_conflicts(error_codes, error_classes) generate_header(argv[2], error_codes, error_classes) generate_source(argv[3], error_codes, error_classes) def die(message=None): sys.stderr.write(message or "Fatal error\n") sys.exit(1) def usage(message=None): sys.stderr.write(__doc__) die(message) def parse_error_definitions_from_file(errors_filename): errors_file = open(errors_filename, 'r') errors_code = compile(errors_file.read(), errors_filename, 'exec') error_codes = [] error_classes = [] eval(errors_code, dict(error_code=lambda *args: error_codes.append(args), error_class=lambda *args: error_classes.append(args))) error_codes.sort(key=lambda x: x[1]) return error_codes, error_classes def check_for_conflicts(error_codes, error_classes): failed = has_duplicate_error_codes(error_codes) if has_duplicate_error_classes(error_classes): failed = True if has_missing_error_codes(error_codes, error_classes): failed = True if failed: die() def has_duplicate_error_codes(error_codes): sorted_by_name = sorted(error_codes, key=lambda x: x[0]) sorted_by_code = sorted(error_codes, key=lambda x: x[1]) failed = False prev_name, prev_code = sorted_by_name[0] for name, code in sorted_by_name[1:]: if name == prev_name: sys.stdout.write('Duplicate name %s with codes %s and %s\n' % (name, code, prev_code)) failed = True prev_name, prev_code = name, code prev_name, prev_code = sorted_by_code[0] for name, code in sorted_by_code[1:]: if code == prev_code: sys.stdout.write('Duplicate code %s with names %s and %s\n' % (code, name, prev_name)) failed = True prev_name, prev_code = name, code return failed def has_duplicate_error_classes(error_classes): names = sorted(ec[0] for ec in error_classes) failed = False prev_name = names[0] for name in names[1:]: if prev_name == name: sys.stdout.write('Duplicate error class name %s\n' % name) failed = True prev_name = name return failed def has_missing_error_codes(error_codes, error_classes): code_names = set(ec[0] for ec in error_codes) failed = False for class_name, class_code_names in error_classes: for name in class_code_names: if name not in code_names: sys.stdout.write('Undeclared error code %s in class %s\n' % (name, class_name)) failed = True return failed def generate_header(filename, error_codes, error_classes): enum_declarations = ',\n '.join('%s = %s' % ec for ec in error_codes) predicate_declarations = ';\n '.join( 'static bool is%s(Error err)' % ec[0] for ec in error_classes) open(filename, 'wb').write(header_template % dict( error_code_enum_declarations=enum_declarations, error_code_class_predicate_declarations=predicate_declarations)) def generate_source(filename, error_codes, error_classes): symbol_to_string_cases = ';\n '.join( 'case %s: return "%s"' % (ec[0], ec[0]) for ec in error_codes) string_to_symbol_cases = ';\n '.join( 'if (name == "%s") return %s' % (ec[0], ec[0]) for ec in error_codes) int_to_symbol_cases = ';\n '.join( 'case %s: return %s' % (ec[0], ec[0]) for ec in error_codes) predicate_definitions = '\n '.join( generate_error_class_predicate_definition(*ec) for ec in error_classes) open(filename, 'wb').write(source_template % dict( symbol_to_string_cases=symbol_to_string_cases, string_to_symbol_cases=string_to_symbol_cases, int_to_symbol_cases=int_to_symbol_cases, error_code_class_predicate_definitions=predicate_definitions)) def generate_error_class_predicate_definition(class_name, code_names): cases = '\n '.join('case %s:' % c for c in code_names) return error_class_predicate_template % dict(class_name=class_name, cases=cases) header_template = '''// AUTO-GENERATED FILE DO NOT EDIT // See src/mongo/base/generate_error_codes.py /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" namespace mongo { /** * This is a generated class containing a table of error codes and their corresponding error * strings. The class is derived from the definitions in src/mongo/base/error_codes.err file. * * Do not update this file directly. Update src/mongo/base/error_codes.err instead. */ class MONGO_CLIENT_API ErrorCodes { public: enum Error { %(error_code_enum_declarations)s, MaxError }; static std::string MONGO_CLIENT_FUNC errorString(Error err); /** * Parses an Error from its "name". Returns UnknownError if "name" is unrecognized. * * NOTE: Also returns UnknownError for the string "UnknownError". */ static Error MONGO_CLIENT_FUNC fromString(const StringData& name); /** * Casts an integer "code" to an Error. Unrecognized codes are preserved, meaning * that the result of a call to fromInt() may not be one of the values in the * Error enumeration. */ static Error MONGO_CLIENT_FUNC fromInt(int code); %(error_code_class_predicate_declarations)s; }; } // namespace mongo ''' source_template = '''// AUTO-GENERATED FILE DO NOT EDIT // See src/mongo/base/generate_error_codes.py /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/error_codes.h" #include #include "mongo/util/mongoutils/str.h" namespace mongo { std::string ErrorCodes::errorString(Error err) { switch (err) { %(symbol_to_string_cases)s; default: return mongoutils::str::stream() << "Location" << err; } } ErrorCodes::Error ErrorCodes::fromString(const StringData& name) { %(string_to_symbol_cases)s; return UnknownError; } ErrorCodes::Error ErrorCodes::fromInt(int code) { return static_cast(code); } %(error_code_class_predicate_definitions)s namespace { BOOST_STATIC_ASSERT(sizeof(ErrorCodes::Error) == sizeof(int)); } // namespace } // namespace mongo ''' error_class_predicate_template = '''bool ErrorCodes::is%(class_name)s(Error err) { switch (err) { %(cases)s return true; default: return false; } } ''' if __name__ == '__main__': main(sys.argv) mongo-cxx-driver-legacy-1.1.2/src/mongo/base/global_initializer.cpp000066400000000000000000000022271273231111400253520ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/global_initializer.h" #include "mongo/base/initializer.h" namespace mongo { Initializer& getGlobalInitializer() { static Initializer theGlobalInitializer; return theGlobalInitializer; } namespace { // Make sure that getGlobalInitializer() is called at least once before main(), and so at least // once in a single-threaded context. Otherwise, static initialization inside // getGlobalInitializer() won't be thread-safe. Initializer* _theGlobalInitializer = &getGlobalInitializer(); } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/global_initializer.h000066400000000000000000000016201273231111400250130ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { class Initializer; /** * Get the process-global initializer object. * * See mongo/base/initializer.h and mongo/base/init.h for information about process * initialization in mongo applications. */ Initializer& getGlobalInitializer(); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/global_initializer_registerer.cpp000066400000000000000000000025141273231111400276040ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/global_initializer_registerer.h" #include #include #include "mongo/base/global_initializer.h" #include "mongo/base/initializer.h" namespace mongo { GlobalInitializerRegisterer::GlobalInitializerRegisterer( const std::string& name, const InitializerFunction& fn, const std::vector& prerequisites, const std::vector& dependents) { Status status = getGlobalInitializer().getInitializerDependencyGraph().addInitializer( name, fn, prerequisites, dependents); if (Status::OK() != status) { std::cerr << "Attempt to add global initializer failed, status: " << status << std::endl; ::abort(); } } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/global_initializer_registerer.h000066400000000000000000000030371273231111400272520ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/initializer_function.h" #include "mongo/base/status.h" namespace mongo { /** * Type representing the act of registering a process-global intialization function. * * Create a module-global instance of this type to register a new initializer, to be run by a * call to a variant of mongo::runGlobalInitializers(). See mongo/base/initializer.h, * mongo/base/init.h and mongo/base/initializer_dependency_graph.h for details. */ class GlobalInitializerRegisterer { MONGO_DISALLOW_COPYING(GlobalInitializerRegisterer); public: GlobalInitializerRegisterer(const std::string& name, const InitializerFunction& fn, const std::vector& prerequisites, const std::vector& dependents); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/init.cpp000066400000000000000000000014111273231111400224440ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/init.h" MONGO_INITIALIZER_GROUP(default, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS) MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(base_init) mongo-cxx-driver-legacy-1.1.2/src/mongo/base/init.h000066400000000000000000000130401273231111400221120ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Utility macros for declaring global initializers * * Should NOT be included by other header files. Include only in source files. * * Initializers are arranged in an acyclic directed dependency graph. Declaring * a cycle will lead to a runtime error. * * Initializer functions take a parameter of type ::mongo::InitializerContext*, and return * a Status. Any status other than Status::OK() is considered a failure that will stop further * intializer processing. */ #pragma once #include "mongo/base/initializer.h" #include "mongo/base/initializer_context.h" #include "mongo/base/initializer_function.h" #include "mongo/base/global_initializer.h" #include "mongo/base/global_initializer_registerer.h" #include "mongo/base/make_string_vector.h" #include "mongo/base/status.h" /** * Convenience parameter representing an empty set of prerequisites for an initializer function. */ #define MONGO_NO_PREREQUISITES (NULL) /** * Convenience parameter representing an empty set of dependents of an initializer function. */ #define MONGO_NO_DEPENDENTS (NULL) /** * Convenience parameter representing the default set of dependents for initializer functions. */ #define MONGO_DEFAULT_PREREQUISITES ("default") /** * Macro to define an initializer function named "NAME" with the default prerequisites, and * no explicit dependents. * * See MONGO_INITIALIZER_GENERAL. * * Usage: * MONGO_INITIALIZER(myModule)(::mongo::InitializerContext* context) { * ... * } */ #define MONGO_INITIALIZER(NAME) \ MONGO_INITIALIZER_WITH_PREREQUISITES(NAME, MONGO_DEFAULT_PREREQUISITES) /** * Macro to define an initializer function named "NAME" that depends on the initializers * specified in PREREQUISITES to have been completed, but names no explicit dependents. * * See MONGO_INITIALIZER_GENERAL. * * Usage: * MONGO_INITIALIZER_WITH_PREREQUISITES(myGlobalStateChecker, * ("globalStateInitialized", "stacktraces"))( * ::mongo::InitializerContext* context) { * } */ #define MONGO_INITIALIZER_WITH_PREREQUISITES(NAME, PREREQUISITES) \ MONGO_INITIALIZER_GENERAL(NAME, PREREQUISITES, MONGO_NO_DEPENDENTS) /** * Macro to define an initializer that depends on PREREQUISITES and has DEPENDENTS as explicit * dependents. * * NAME is any legitimate name for a C++ symbol. * PREREQUISITES is a tuple of 0 or more string literals, i.e., ("a", "b", "c"), or () * DEPENDENTS is a tuple of 0 or more string literals. * * At run time, the full set of prerequisites for NAME will be computed as the union of the * explicit PREREQUISITES and the set of all other mongo initializers that name NAME in their * list of dependents. * * Usage: * MONGO_INITIALIZER_GENERAL(myInitializer, * ("myPrereq1", "myPrereq2", ...), * ("myDependent1", "myDependent2", ...))( * ::mongo::InitializerContext* context) { * } * * TODO: May want to be able to name the initializer separately from the function name. * A form that takes an existing function or that lets the programmer supply the name * of the function to declare would be options. */ #define MONGO_INITIALIZER_GENERAL(NAME, PREREQUISITES, DEPENDENTS) \ ::mongo::Status _MONGO_INITIALIZER_FUNCTION_NAME(NAME)(::mongo::InitializerContext*); \ namespace { \ ::mongo::GlobalInitializerRegisterer _mongoInitializerRegisterer_##NAME( \ #NAME, \ _MONGO_INITIALIZER_FUNCTION_NAME(NAME), \ MONGO_MAKE_STRING_VECTOR PREREQUISITES, \ MONGO_MAKE_STRING_VECTOR DEPENDENTS); \ } \ ::mongo::Status _MONGO_INITIALIZER_FUNCTION_NAME(NAME) /** * Macro to define an initializer group. * * An initializer group is an initializer that performs no actions. It is useful for organizing * initialization steps into phases, such as "all global parameter declarations completed", "all * global parameters initialized". */ #define MONGO_INITIALIZER_GROUP(NAME, PREREQUISITES, DEPENDENTS) \ MONGO_INITIALIZER_GENERAL(NAME, PREREQUISITES, DEPENDENTS)(::mongo::InitializerContext*) { \ return ::mongo::Status::OK(); \ } /** * Macro to produce a name for a mongo initializer function for an initializer operation * named "NAME". */ #define _MONGO_INITIALIZER_FUNCTION_NAME(NAME) _mongoInitializerFunction_##NAME #define MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(NAME) \ namespace mongo { \ void _mongoInitializerFunctionAssure_##NAME() {} \ } mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer.cpp000066400000000000000000000073651273231111400240420ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/initializer.h" #include #include "mongo/util/assert_util.h" #include "mongo/base/global_initializer.h" namespace mongo { Initializer::Initializer() {} Initializer::~Initializer() {} /* This array of function pointers is necessary to force inclusion of * translation units with global initializers when linking against a static * archive version of the client. In their absence, the related code may * resolve no symbols in a potential output binary, failing to pull in the * initializers and leaving the client in a broken state. * * Working around this with --whole-archive or an equivalent is painful where * possible and renders the static archive useless where not possible (on * windows). * * Sorry for the hack... */ #define INSTALL_FUNCTION(NAME) void _mongoInitializerFunctionAssure_##NAME(); #include "mongo/base/initializer_functions.h" #undef INSTALL_FUNCTION void (*_mongoGlobalInitializers[])() = { #define INSTALL_FUNCTION(NAME) &(_mongoInitializerFunctionAssure_##NAME), #include "mongo/base/initializer_functions.h" #undef INSTALL_FUNCTION NULL}; Status Initializer::execute(const InitializerContext::ArgumentVector& args, const InitializerContext::EnvironmentMap& env) const { std::vector sortedNodes; Status status = _graph.topSort(&sortedNodes); if (Status::OK() != status) return status; InitializerContext context(args, env); for (size_t i = 0; i < sortedNodes.size(); ++i) { InitializerFunction fn = _graph.getInitializerFunction(sortedNodes[i]); if (!fn) { return Status(ErrorCodes::InternalError, "topSort returned a node that has no associated function: \"" + sortedNodes[i] + '"'); } try { status = fn(&context); } catch (const DBException& xcp) { return xcp.toStatus(); } if (Status::OK() != status) return status; } return Status::OK(); } Status runGlobalInitializers(const InitializerContext::ArgumentVector& args, const InitializerContext::EnvironmentMap& env) { return getGlobalInitializer().execute(args, env); } Status runGlobalInitializers(int argc, const char* const* argv, const char* const* envp) { InitializerContext::ArgumentVector args(argc); std::copy(argv, argv + argc, args.begin()); InitializerContext::EnvironmentMap env; if (envp) { for (; *envp; ++envp) { const char* firstEqualSign = strchr(*envp, '='); if (!firstEqualSign) { return Status(ErrorCodes::BadValue, "malformed environment block"); } env[std::string(*envp, firstEqualSign)] = std::string(firstEqualSign + 1); } } return runGlobalInitializers(args, env); } void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* const* envp) { Status status = runGlobalInitializers(argc, argv, envp); if (!status.isOK()) { std::cerr << "Failed global initialization: " << status << std::endl; abort(); } } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer.h000066400000000000000000000055471273231111400235070ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/initializer_context.h" #include "mongo/base/initializer_dependency_graph.h" #include "mongo/base/status.h" #include "mongo/client/export_macros.h" namespace mongo { /** * Class representing an initialization process. * * Such a process is described by a directed acyclic graph of initialization operations, the * InitializerDependencyGraph. One constructs an initialization process by adding nodes and * edges to the graph. Then, one executes the process, causing each initialization operation to * execute in an order that respects the programmer-established prerequistes. */ class Initializer { MONGO_DISALLOW_COPYING(Initializer); public: Initializer(); ~Initializer(); /** * Get the initializer dependency graph, presumably for the purpose of adding more nodes. */ InitializerDependencyGraph& getInitializerDependencyGraph() { return _graph; } /** * Execute the initializer process, using the given argv and environment data as input. * * Returns Status::OK on success. All other returns constitute initialization failures, * and the thing being initialized should be considered dead in the water. */ Status execute(const InitializerContext::ArgumentVector& args, const InitializerContext::EnvironmentMap& env) const; private: InitializerDependencyGraph _graph; }; /** * Run the global initializers. * * It's a programming error for this to fail, but if it does it will return a status other * than Status::OK. * * This means that the few initializers that might want to terminate the program by failing * should probably arrange to terminate the process themselves. */ Status runGlobalInitializers(const InitializerContext::ArgumentVector& args, const InitializerContext::EnvironmentMap& env); Status runGlobalInitializers(int argc, const char* const* argv, const char* const* envp); /** * Same as runGlobalInitializers(), except prints a brief message to std::cerr * and terminates the process on failure. */ void runGlobalInitializersOrDie(int argc, const char* const* argv, const char* const* envp); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_context.cpp000066400000000000000000000014771273231111400256040ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/initializer_context.h" namespace mongo { InitializerContext::InitializerContext(const ArgumentVector& args, const EnvironmentMap& env) : _args(args), _env(env) {} } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_context.h000066400000000000000000000026511273231111400252440ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/base/disallow_copying.h" namespace mongo { /** * Context of an initialization process. Passed as a parameter to initialization functions. * * See mongo/base/initializer.h and mongo/base/initializer_dependency_graph.h for more details. */ class InitializerContext { MONGO_DISALLOW_COPYING(InitializerContext); public: typedef std::vector ArgumentVector; typedef std::map EnvironmentMap; InitializerContext(const ArgumentVector& args, const EnvironmentMap& env); const ArgumentVector& args() const { return _args; } const EnvironmentMap& env() const { return _env; } private: ArgumentVector _args; EnvironmentMap _env; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_dependency_graph.cpp000066400000000000000000000135041273231111400274110ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/initializer_dependency_graph.h" #include #include #include namespace mongo { InitializerDependencyGraph::InitializerDependencyGraph() {} InitializerDependencyGraph::~InitializerDependencyGraph() {} Status InitializerDependencyGraph::addInitializer(const std::string& name, const InitializerFunction& fn, const std::vector& prerequisites, const std::vector& dependents) { if (!fn) return Status(ErrorCodes::BadValue, "Illegal to supply a NULL function"); NodeData& newNode = _nodes[name]; if (newNode.fn) { return Status(ErrorCodes::DuplicateKey, name); } newNode.fn = fn; for (size_t i = 0; i < prerequisites.size(); ++i) { newNode.prerequisites.insert(prerequisites[i]); } for (size_t i = 0; i < dependents.size(); ++i) { _nodes[dependents[i]].prerequisites.insert(name); } return Status::OK(); } InitializerFunction InitializerDependencyGraph::getInitializerFunction( const std::string& name) const { NodeMap::const_iterator iter = _nodes.find(name); if (iter == _nodes.end()) return InitializerFunction(); return iter->second.fn; } Status InitializerDependencyGraph::topSort(std::vector* sortedNames) const { /* * This top-sort is implemented by performing a depth-first traversal of the dependency * graph, once for each node. "visitedNodeNames" tracks the set of node names ever visited, * and it is used to prune each DFS. A node that has been visited once on any DFS is never * visited again. Complexity of this implementation is O(n+m) where "n" is the number of * nodes and "m" is the number of prerequisite edges. Space complexity is O(n), in both * stack space and size of the "visitedNodeNames" set. * * "inProgressNodeNames" is used to detect and report cycles. */ std::vector inProgressNodeNames; unordered_set visitedNodeNames; sortedNames->clear(); for (NodeMap::const_iterator iter = _nodes.begin(), end = _nodes.end(); iter != end; ++iter) { Status status = recursiveTopSort(_nodes, *iter, &inProgressNodeNames, &visitedNodeNames, sortedNames); if (Status::OK() != status) return status; } return Status::OK(); } Status InitializerDependencyGraph::recursiveTopSort(const NodeMap& nodeMap, const Node& currentNode, std::vector* inProgressNodeNames, unordered_set* visitedNodeNames, std::vector* sortedNames) { /* * The top sort is performed by depth-first traversal starting at each node in the * dependency graph, short-circuited any time a node is seen that has already been visited * in any traversal. "visitedNodeNames" is the set of nodes that have been successfully * visited, while "inProgressNodeNames" are nodes currently in the exploration chain. This * structure is kept explicitly to facilitate cycle detection. * * This function implements a depth-first traversal, and is called once for each node in the * graph by topSort(), above. */ if ((*visitedNodeNames).count(currentNode.first)) return Status::OK(); if (!currentNode.second.fn) return Status(ErrorCodes::BadValue, currentNode.first); inProgressNodeNames->push_back(currentNode.first); std::vector::iterator firstOccurence = std::find(inProgressNodeNames->begin(), inProgressNodeNames->end(), currentNode.first); if (firstOccurence + 1 != inProgressNodeNames->end()) { sortedNames->clear(); std::copy(firstOccurence, inProgressNodeNames->end(), std::back_inserter(*sortedNames)); std::ostringstream os; os << "Cycle in dependendcy graph: " << sortedNames->at(0); for (size_t i = 1; i < sortedNames->size(); ++i) os << " -> " << sortedNames->at(i); return Status(ErrorCodes::GraphContainsCycle, os.str()); } for (unordered_set::const_iterator iter = currentNode.second.prerequisites.begin(), end = currentNode.second.prerequisites.end(); iter != end; ++iter) { NodeMap::const_iterator nextNode = nodeMap.find(*iter); if (nextNode == nodeMap.end()) return Status(ErrorCodes::BadValue, *iter); Status status = recursiveTopSort( nodeMap, *nextNode, inProgressNodeNames, visitedNodeNames, sortedNames); if (Status::OK() != status) return status; } sortedNames->push_back(currentNode.first); if (inProgressNodeNames->back() != currentNode.first) return Status(ErrorCodes::InternalError, "inProgressNodeNames stack corrupt"); inProgressNodeNames->pop_back(); visitedNodeNames->insert(currentNode.first); return Status::OK(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_dependency_graph.h000066400000000000000000000115421273231111400270560ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/initializer_function.h" #include "mongo/base/status.h" #include "mongo/platform/unordered_map.h" #include "mongo/platform/unordered_set.h" namespace mongo { /** * Representation of a dependency graph of "initialization operations." * * Each operation has a unique name, a function object implementing the operation's behavior, * and a set of prerequisite operations, which may be empty. A legal graph contains no cycles. * * Instances of this class are used in two phases. In the first phase, the graph is constructed * by repeated calls to addInitializer(). In the second phase, a user calls the topSort() * method to produce an initialization order that respects the dependencies among operations, and * then uses the getInitializerFunction() to get the behavior function for each operation, in * turn. * * Concurrency Notes: The user is responsible for synchronization. Multiple threads may * simultaneously call the const functions, getInitializerFunction and topSort, on the same * instance of InitializerDependencyGraph. However, no thread may call addInitializer while any * thread is executing those functions or addInitializer on the same instance. */ class InitializerDependencyGraph { MONGO_DISALLOW_COPYING(InitializerDependencyGraph); public: InitializerDependencyGraph(); ~InitializerDependencyGraph(); /** * Add a new initializer node, named "name", to the dependency graph, with the given * behavior, "fn", and the given "prerequisites" (input dependencies) and "dependents" * (output dependencies). * * If "!fn" (fn is NULL in function pointer parlance), returns status with code * ErrorCodes::badValue. If "name" is a duplicate of a name already present in the graph, * returns "ErrorCodes::duplicateKey". Otherwise, returns Status::OK() and adds the new node * to the graph. Note that cycles in the dependency graph are not discovered in this phase. * Rather, they're discovered by topSort, below. */ Status addInitializer(const std::string& name, const InitializerFunction& fn, const std::vector& prerequisites, const std::vector& dependents); /** * Given a dependency operation node named "name", return its behavior function. Returns * a value that evaluates to "false" in boolean context, otherwise. */ InitializerFunction getInitializerFunction(const std::string& name) const; /** * Construct a topological sort of the dependency graph, and store that order into * "sortedNames". Returns Status::OK() on success. * * If the graph contains a cycle, returns ErrorCodes::graphContainsCycle, and "sortedNames" * is an ordered sequence of nodes involved in a cycle. In this case, the first and last * element of "sortedNames" will be equal. * * If any node in the graph names a prerequisite that was never added to the graph via * addInitializer, this function will return ErrorCodes::badValue. * * Any other return value indicates an internal error, and should not occur. */ Status topSort(std::vector* sortedNames) const; private: struct NodeData { InitializerFunction fn; unordered_set prerequisites; }; typedef unordered_map NodeMap; typedef NodeMap::value_type Node; /** * Helper function to recursively top-sort a graph. Used by topSort(). */ static Status recursiveTopSort(const NodeMap& nodeMap, const Node& currentNode, std::vector* inProgressNodeNames, unordered_set* visitedNodeNames, std::vector* sortedNames); /** * Map of all named nodes. Nodes named as prerequisites or dependents but not explicitly * added via addInitializer will either be absent from this map or be present with * NodeData::fn set to a false-ish value. */ NodeMap _nodes; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_function.h000066400000000000000000000020531273231111400254010ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" #include "mongo/stdx/functional.h" namespace mongo { class InitializerContext; /** * An InitializerFunction implements the behavior of an initializer operation. * * On successful execution, an InitializerFunction returns Status::OK(). It may * inspect and mutate the supplied InitializerContext. */ typedef stdx::function InitializerFunction; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/initializer_functions.h000066400000000000000000000032411273231111400255640ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/config.h" INSTALL_FUNCTION(base_init) // "default" INSTALL_FUNCTION(bson_oid) // "OIDGeneration" INSTALL_FUNCTION(logger_logstream_builder) // "LogstreamBuilder" INSTALL_FUNCTION(logger_logger) // "GlobalLogManager" #ifdef MONGO_SSL INSTALL_FUNCTION(client_sasl_client_authenticate_impl) // "SaslClientAuthenticateFunction" INSTALL_FUNCTION(client_native_sasl_client_session) // "NativeSaslClientContext" #endif #ifdef MONGO_SASL INSTALL_FUNCTION( client_cyrus_sasl_client_session) // "CyrusSaslAllocatorsAndMutexes,CyrusSaslClientContext" INSTALL_FUNCTION( client_sasl_sspi) // "SaslSspiClientPlugin,SaslCramClientPlugin,SaslPlainClientPlugin" #endif INSTALL_FUNCTION(util_fail_point_service) // "FailPointRegistry,AllFailPointsRegistered" INSTALL_FUNCTION(util_net_socket_poll) // "DynamicLinkWin32Poll" INSTALL_FUNCTION(util_net_ssl_manager) // "SSLManager" INSTALL_FUNCTION(util_net_sock) // "SockWSAStartup" INSTALL_FUNCTION(util_time_support) // "Init32TimeSupport" mongo-cxx-driver-legacy-1.1.2/src/mongo/base/make_string_vector.cpp000066400000000000000000000020271273231111400253720ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/make_string_vector.h" #include #include #include namespace mongo { std::vector _makeStringVector(int ignored, ...) { va_list ap; va_start(ap, ignored); std::vector result; const char* arg = NULL; while ((arg = va_arg(ap, const char*))) result.push_back(arg); va_end(ap); return result; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/make_string_vector.h000066400000000000000000000032361273231111400250420ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include /** * Utility macro to construct a std::vector from a sequence of C-style * strings. * * Usage: MONGO_MAKE_STRING_VECTOR("a", "b", "c") returns a vector containing * std::strings "a", "b", "c", in that order. */ #define MONGO_MAKE_STRING_VECTOR(...) ::mongo::_makeStringVector(0, __VA_ARGS__, NULL) namespace mongo { /** * Create a vector of strings from varargs of C-style strings. * * WARNING: Only intended for use by MONGO_MAKE_STRING_VECTOR macro, defined above. Aborts * ungracefully if you misuse it, so stick to the macro. * * The first parameter is ignored in all circumstances. The subsequent parameters must be * const char* C-style strings, or NULL. Of these parameters, at least one must be * NULL. Parameters at and beyond the NULL are not inserted. Typically, the NULL will be * the last parameter. The MONGO_MAKE_STRING_VECTOR macro enforces this. * * Returns a vector of std::strings. */ std::vector _makeStringVector(int ignored, ...); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/owned_pointer_vector.h000066400000000000000000000107211273231111400254100ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" namespace mongo { /** * An std::vector wrapper that deletes pointers within a vector on destruction. The objects * referenced by the vector's pointers are 'owned' by an object of this class. * NOTE that an OwnedPointerVector wraps an std::vector. */ template class OwnedPointerVector { MONGO_DISALLOW_COPYING(OwnedPointerVector); public: OwnedPointerVector() {} ~OwnedPointerVector() { clear(); } /** * Takes ownership of all pointers contained in 'other'. * NOTE: argument is intentionally taken by value. */ OwnedPointerVector(std::vector other) { _vector.swap(other); } /** * Takes ownership of all pointers contained in 'other'. * NOTE: argument is intentionally taken by value. */ OwnedPointerVector& operator=(std::vector other) { clear(); _vector.swap(other); return *this; } typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::const_reverse_iterator const_reverse_iterator; /** Access the vector. */ const std::vector& vector() const { return _vector; } std::vector& mutableVector() { return _vector; } std::size_t size() const { return _vector.size(); } bool empty() const { return _vector.empty(); } const_iterator begin() const { return _vector.begin(); } const_reverse_iterator rbegin() const { return _vector.rbegin(); } const_iterator end() const { return _vector.end(); } const_reverse_iterator rend() const { return _vector.rend(); } T* operator[](size_t i) const { return _vector[i]; } T* back() const { return _vector.back(); } T* front() const { return _vector.front(); } void push_back(T* ptr) { _vector.push_back(ptr); } /** * Deletes all pointers in the vector, then sets its size to 0. */ void clear(); /** * Deletes the pointer at 'it', then erases it from the vector. */ void erase(const_iterator it) { delete *it; _vector.erase(toNonConstIter(it)); } void erase(const_iterator begin, const_iterator end) { for (const_iterator it = begin; it != end; ++it) { delete *it; } _vector.erase(toNonConstIter(begin), toNonConstIter(end)); } // // extensions // /** * Releases the entire vector to allow you to transfer ownership. * * Leaves the OwnedPointerVector empty. * Named after the similar method and pattern in std::auto_ptr. */ std::vector release() { std::vector out; out.swap(_vector); return out; } /** * Releases ownership of a single element. * * Sets that element to NULL and does not change size(). */ T* releaseAt(size_t i) { T* out = _vector[i]; _vector[i] = NULL; return out; } T* popAndReleaseBack() { T* out = _vector.back(); _vector.pop_back(); return out; } void popAndDeleteBack() { delete popAndReleaseBack(); } private: typename std::vector::iterator toNonConstIter(const_iterator it) { // This is needed for a few cases where c++03 vectors require non-const iterators that // were relaxed in c++11 to allow const_iterators. It can go away when we require c++11. return _vector.begin() + (it - begin()); } std::vector _vector; }; template inline void OwnedPointerVector::clear() { for (typename std::vector::iterator i = _vector.begin(); i != _vector.end(); ++i) { delete *i; } _vector.clear(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/parse_number.cpp000066400000000000000000000217671273231111400242030ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/base/parse_number.h" #include #include #include #include #include #include "mongo/platform/cstdint.h" namespace mongo { /** * Returns the value of the digit "c", with the same conversion behavior as strtol. * * Assumes "c" is an ASCII character or UTF-8 octet. */ static uint8_t _digitValue(char c) { if (c >= '0' && c <= '9') return uint8_t(c - '0'); if (c >= 'a' && c <= 'z') return uint8_t(c - 'a' + 10); if (c >= 'A' && c <= 'Z') return uint8_t(c - 'A' + 10); return 36; // Illegal digit value for all supported bases. } /** * Assuming "stringValue" represents a parseable number, extracts the sign and returns a * substring with any sign characters stripped away. "*isNegative" is set to true if the * number is negative, and false otherwise. */ static inline StringData _extractSign(const StringData& stringValue, bool* isNegative) { if (stringValue.empty()) { *isNegative = false; return stringValue; } bool foundSignMarker; switch (stringValue[0]) { case '-': foundSignMarker = true; *isNegative = true; break; case '+': foundSignMarker = true; *isNegative = false; break; default: foundSignMarker = false; *isNegative = false; break; } if (foundSignMarker) return stringValue.substr(1); return stringValue; } /** * Assuming "stringValue" represents a parseable number, determines what base to use given * "inputBase". Stores the correct base into "*outputBase". Follows strtol rules. If * "inputBase" is not 0, *outputBase is set to "inputBase". Otherwise, if "stringValue" starts * with "0x" or "0X", sets outputBase to 16, or if it starts with 0, sets outputBase to 8. * * Returns stringValue, unless it sets *outputBase to 16, in which case it will strip off the * "0x" or "0X" prefix, if present. */ static inline StringData _extractBase(const StringData& stringValue, int inputBase, int* outputBase) { const StringData hexPrefixLower("0x", StringData::LiteralTag()); const StringData hexPrefixUpper("0X", StringData::LiteralTag()); if (inputBase == 0) { if (stringValue.size() > 2 && (stringValue.startsWith(hexPrefixLower) || stringValue.startsWith(hexPrefixUpper))) { *outputBase = 16; return stringValue.substr(2); } if (stringValue.size() > 1 && stringValue[0] == '0') { *outputBase = 8; return stringValue; } *outputBase = 10; return stringValue; } else { *outputBase = inputBase; if (inputBase == 16 && (stringValue.startsWith(hexPrefixLower) || stringValue.startsWith(hexPrefixUpper))) { return stringValue.substr(2); } return stringValue; } } template Status parseNumberFromStringWithBase(const StringData& stringValue, int base, NumberType* result) { typedef ::std::numeric_limits limits; if (base == 1 || base < 0 || base > 36) return Status(ErrorCodes::BadValue, "Invalid base", 0); bool isNegative = false; StringData str = _extractBase(_extractSign(stringValue, &isNegative), base, &base); if (str.empty()) return Status(ErrorCodes::FailedToParse, "No digits"); NumberType n(0); if (isNegative) { if (limits::is_signed) { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) { return Status(ErrorCodes::FailedToParse, "Bad digit \"" + str.substr(i, 1).toString() + "\" while parsing " + stringValue.toString()); } // MSVC: warning C4146: unary minus operator applied to unsigned type, result still unsigned // This code is statically known to be dead when NumberType is unsigned, so the warning is not real #pragma warning(push) #pragma warning(disable : 4146) if ((NumberType(limits::min() / base) > n) || ((limits::min() - NumberType(n * base)) > -digitValue)) { #pragma warning(pop) return Status(ErrorCodes::FailedToParse, "Underflow"); } n *= NumberType(base); n -= NumberType(digitValue); } } else { return Status(ErrorCodes::FailedToParse, "Negative value"); } } else { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) { return Status(ErrorCodes::FailedToParse, "Bad digit \"" + str.substr(i, 1).toString() + "\" while parsing " + stringValue.toString()); } if ((NumberType(limits::max() / base) < n) || (NumberType(limits::max() - n * base) < digitValue)) { return Status(ErrorCodes::FailedToParse, "Overflow"); } n *= NumberType(base); n += NumberType(digitValue); } } *result = n; return Status::OK(); } // Definition of the various supported implementations of parseNumberFromStringWithBase. #define DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(NUMBER_TYPE) \ template MONGO_CLIENT_API Status MONGO_CLIENT_FUNC \ parseNumberFromStringWithBase(const StringData&, int, NUMBER_TYPE*); DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(long) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(long long) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned long) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned long long) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(short) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned short) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned int) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int8_t); DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(uint8_t); #undef DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE #ifdef _WIN32 namespace { /** * Converts ascii c-locale uppercase characters to lower case, leaves other char values * unchanged. */ char toLowerAscii(char c) { if (isascii(c) && isupper(c)) return _tolower(c); return c; } } // namespace #endif // defined(_WIN32) template <> Status parseNumberFromStringWithBase(const StringData& stringValue, int base, double* result) { if (base != 0) { return Status(ErrorCodes::BadValue, "Must pass 0 as base to parseNumberFromStringWithBase."); } if (stringValue.empty()) return Status(ErrorCodes::FailedToParse, "Empty string"); if (isspace(stringValue[0])) return Status(ErrorCodes::FailedToParse, "Leading whitespace"); std::string str = stringValue.toString(); const char* cStr = str.c_str(); char* endp; errno = 0; double d = strtod(cStr, &endp); int actualErrno = errno; if (endp != stringValue.size() + cStr) { #ifdef _WIN32 // The Windows libc implementation of strtod cannot parse +/-infinity or nan, // so handle that here. std::transform(str.begin(), str.end(), str.begin(), toLowerAscii); if (str == StringData("nan", StringData::LiteralTag())) { *result = std::numeric_limits::quiet_NaN(); return Status::OK(); } else if (str == StringData("+infinity", StringData::LiteralTag()) || str == StringData("infinity", StringData::LiteralTag())) { *result = std::numeric_limits::infinity(); return Status::OK(); } else if (str == StringData("-infinity", StringData::LiteralTag())) { *result = -std::numeric_limits::infinity(); return Status::OK(); } #endif // defined(_WIN32) return Status(ErrorCodes::FailedToParse, "Did not consume whole number."); } if (actualErrno == ERANGE) return Status(ErrorCodes::FailedToParse, "Out of range"); *result = d; return Status::OK(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/parse_number.h000066400000000000000000000040001273231111400236250ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Utility functions for parsing numbers from strings. */ #pragma once #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" namespace mongo { /** * Parses a number out of a StringData. * * Parses "stringValue", interpreting it as a number of the given "base". On success, stores * the parsed value into "*result" and returns Status::OK(). * * Valid values for "base" are 2-36, with 0 meaning "choose the base by inspecting the prefix * on the number", as in strtol. Returns Status::BadValue if an illegal value is supplied for * "base". * * The entirety of the string must consist of digits in the given base, except optionally the * first character may be "+" or "-", and hexadecimal numbers may begin "0x". Same as strtol, * without the property of stripping whitespace at the beginning, and fails to parse if there * are non-digit characters at the end of the string. * * See parse_number.cpp for the available instantiations, and add any new instantiations there. */ template MONGO_CLIENT_API Status MONGO_CLIENT_FUNC parseNumberFromStringWithBase(const StringData& stringValue, int base, NumberType* result); template static Status parseNumberFromString(const StringData& stringValue, NumberType* result) { return parseNumberFromStringWithBase(stringValue, 0, result); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/parse_number_test.cpp000066400000000000000000000346661273231111400252440ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongo/base/parse_number.h" #include "mongo/base/status.h" #include "mongo/platform/cstdint.h" #include "mongo/platform/float_utils.h" #include "mongo/util/mongoutils/str.h" // for str::stream()! #include "mongo/unittest/unittest.h" #define ASSERT_PARSES(TYPE, INPUT_STRING, EXPECTED_VALUE) \ do { \ TYPE v; \ ASSERT_OK(parseNumberFromString(INPUT_STRING, &v)); \ ASSERT_EQUALS(static_cast(EXPECTED_VALUE), v); \ } while (false) #define ASSERT_PARSES_WITH_BASE(TYPE, INPUT_STRING, BASE, EXPECTED_VALUE) \ do { \ TYPE v; \ ASSERT_OK(parseNumberFromStringWithBase(INPUT_STRING, BASE, &v)); \ ASSERT_EQUALS(static_cast(EXPECTED_VALUE), v); \ } while (false) namespace mongo { namespace { template class CommonNumberParsingTests { public: typedef _NumberType NumberType; typedef std::numeric_limits Limits; static void TestRejectingBadBases() { NumberType ignored; ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("10", 1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("-10", 37, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase(" ", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("f", 37, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("^%", -1, &ignored)); } static void TestParsingNonNegatives() { ASSERT_PARSES(NumberType, "10", 10); ASSERT_PARSES(NumberType, "0", 0); ASSERT_PARSES(NumberType, "1", 1); ASSERT_PARSES(NumberType, "0xff", 0xff); ASSERT_PARSES(NumberType, "077", 077); } static void TestParsingNegatives() { if (Limits::is_signed) { ASSERT_PARSES(NumberType, "-10", -10); ASSERT_PARSES(NumberType, "-0xff", -0xff); ASSERT_PARSES(NumberType, "-077", -077); } else { NumberType ignored; ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-0xff", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-077", &ignored)); } } static void TestParsingGarbage() { NumberType ignored; ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(" ", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(" 10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("15b", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("--10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("++10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("--10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0x+10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0x-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0+10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1+10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1-10", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("48*3", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0x", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+0x", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-0x", &ignored)); } static void TestParsingWithExplicitBase() { NumberType x; ASSERT_PARSES_WITH_BASE(NumberType, "15b", 16, 0x15b); ASSERT_PARSES_WITH_BASE(NumberType, "77", 8, 077); ASSERT_PARSES_WITH_BASE(NumberType, "z", 36, 35); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("1b", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("80", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("0X", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("+0X", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 16, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 8, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0x", 10, &x)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromStringWithBase("-0X", 10, &x)); } static void TestParsingLimits() { using namespace mongoutils; NumberType ignored; ASSERT_PARSES(NumberType, std::string(str::stream() << Limits::max()), Limits::max()); ASSERT_PARSES(NumberType, std::string(str::stream() << Limits::min()), Limits::min()); ASSERT_EQUALS( ErrorCodes::FailedToParse, parseNumberFromString(std::string(str::stream() << Limits::max() << '0'), &ignored)); if (Limits::is_signed) ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(std::string(str::stream() << Limits::min() << '0'), &ignored)); } }; #define GENERAL_NUMBER_TESTS(SHORT_NAME, TYPE) \ class ParseNumberTests##SHORT_NAME : public unittest::Test { \ public: \ typedef CommonNumberParsingTests TestFns; \ }; \ TEST_F(ParseNumberTests##SHORT_NAME, RejectBadBases) { \ TestFns::TestRejectingBadBases(); \ } \ TEST_F(ParseNumberTests##SHORT_NAME, ParseNonNegatives) { \ TestFns::TestParsingNonNegatives(); \ } \ TEST_F(ParseNumberTests##SHORT_NAME, ParseNegatives) { \ TestFns::TestParsingNegatives(); \ } \ TEST_F(ParseNumberTests##SHORT_NAME, ParseGarbage) { \ TestFns::TestParsingGarbage(); \ } \ TEST_F(ParseNumberTests##SHORT_NAME, ParseWithExplicitBase) { \ TestFns::TestParsingWithExplicitBase(); \ } \ TEST_F(ParseNumberTests##SHORT_NAME, TestParsingLimits) { \ TestFns::TestParsingLimits(); \ } GENERAL_NUMBER_TESTS(Short, short) GENERAL_NUMBER_TESTS(Int, int) GENERAL_NUMBER_TESTS(Long, long) GENERAL_NUMBER_TESTS(LongLong, long long) GENERAL_NUMBER_TESTS(UnsignedShort, unsigned short) GENERAL_NUMBER_TESTS(UnsignedInt, unsigned int) GENERAL_NUMBER_TESTS(UnsignedLong, unsigned long) GENERAL_NUMBER_TESTS(UnsignedLongLong, unsigned long long) GENERAL_NUMBER_TESTS(Int16, int16_t); GENERAL_NUMBER_TESTS(Int32, int32_t); GENERAL_NUMBER_TESTS(Int64, int64_t); GENERAL_NUMBER_TESTS(UInt16, uint16_t); GENERAL_NUMBER_TESTS(UInt32, uint32_t); GENERAL_NUMBER_TESTS(UInt64, uint64_t); TEST(ParseNumber, NotNullTerminated) { ASSERT_PARSES(int, StringData("1234", 3), 123); } TEST(ParseNumber, Int8) { int8_t ignored; ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-129", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-130", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-900", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("128", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("130", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("900", &ignored)); for (int32_t i = -128; i <= 127; ++i) ASSERT_PARSES(int8_t, std::string(mongoutils::str::stream() << i), i); } TEST(ParseNumber, UInt8) { uint8_t ignored; ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-129", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-130", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-900", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+256", &ignored)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("+900", &ignored)); for (uint32_t i = 0; i <= 255; ++i) ASSERT_PARSES(uint8_t, std::string(mongoutils::str::stream() << i), i); } TEST(Double, TestRejectingBadBases) { double ignored; // Only supported base for parseNumberFromStringWithBase is 0. ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 1, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 8, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 10, &ignored)); ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 16, &ignored)); } TEST(Double, TestParsingGarbage) { double d; CommonNumberParsingTests::TestParsingGarbage(); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1.0.1", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1.0-1", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(" 1.0", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1.0P4", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e6 ", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(" 1e6", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e6 ", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString(" 1e6", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("0xabcab.defPa", &d)); ASSERT_EQUALS( ErrorCodes::FailedToParse, parseNumberFromString(StringData("1.0\0garbage", StringData::LiteralTag()), &d)); } TEST(Double, TestParsingOverflow) { double d; ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e309", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e309", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e-400", &d)); ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e-400", &d)); } TEST(Double, TestParsingNan) { double d = 0; ASSERT_OK(parseNumberFromString("NaN", &d)); ASSERT_TRUE(isNaN(d)); } TEST(Double, TestParsingInfinity) { double d = 0; ASSERT_OK(parseNumberFromString("infinity", &d)); ASSERT_TRUE(isInf(d)); d = 0; ASSERT_OK(parseNumberFromString("-Infinity", &d)); ASSERT_TRUE(isInf(d)); } TEST(Double, TestParsingNormal) { ASSERT_PARSES(double, "10", 10); ASSERT_PARSES(double, "0", 0); ASSERT_PARSES(double, "1", 1); ASSERT_PARSES(double, "-10", -10); ASSERT_PARSES(double, "1e8", 1e8); ASSERT_PARSES(double, "1e-8", 1e-8); ASSERT_PARSES(double, "12e-8", 12e-8); ASSERT_PARSES(double, "-485.381e-8", -485.381e-8); #if !(defined(_WIN32) || defined(__sunos__)) // Parse hexadecimal representations of a double. Hex literals not supported by MSVC, and // not parseable by the Windows SDK libc or the Solaris libc in the mode we build. // See SERVER-14131. ASSERT_PARSES(double, "0xff", 0xff); ASSERT_PARSES(double, "-0xff", -0xff); ASSERT_PARSES(double, "0xabcab.defdefP-10", 0xabcab.defdefP-10); #endif } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/status-inl.h000066400000000000000000000045261273231111400232630ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { inline Status Status::OK() { return Status(); } inline Status::Status(const Status& other) : _error(other._error) { ref(_error); } inline Status& Status::operator=(const Status& other) { ref(other._error); unref(_error); _error = other._error; return *this; } #if __cplusplus >= 201103L inline Status::Status(Status&& other) noexcept : _error(other._error) { other._error = nullptr; } inline Status& Status::operator=(Status&& other) noexcept { unref(_error); _error = other._error; other._error = nullptr; return *this; } #endif // __cplusplus >= 201103L inline Status::~Status() { unref(_error); } inline bool Status::isOK() const { return code() == ErrorCodes::OK; } inline ErrorCodes::Error Status::code() const { return _error ? _error->code : ErrorCodes::OK; } inline std::string Status::codeString() const { return ErrorCodes::errorString(code()); } inline std::string Status::reason() const { return _error ? _error->reason : std::string(); } inline int Status::location() const { return _error ? _error->location : 0; } inline AtomicUInt32::WordType Status::refCount() const { return _error ? _error->refs.load() : 0; } inline Status::Status() : _error(NULL) {} inline void Status::ref(ErrorInfo* error) { if (error) error->refs.fetchAndAdd(1); } inline void Status::unref(ErrorInfo* error) { if (error && (error->refs.subtractAndFetch(1) == 0)) delete error; } inline bool MONGO_CLIENT_FUNC operator==(const ErrorCodes::Error lhs, const Status& rhs) { return rhs == lhs; } inline bool MONGO_CLIENT_FUNC operator!=(const ErrorCodes::Error lhs, const Status& rhs) { return rhs != lhs; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/status.cpp000066400000000000000000000046701273231111400230360ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/status.h" #include #include namespace mongo { Status::ErrorInfo::ErrorInfo(ErrorCodes::Error aCode, const StringData& aReason, int aLocation) : code(aCode), reason(aReason.toString()), location(aLocation) {} Status::ErrorInfo* Status::ErrorInfo::create(ErrorCodes::Error c, const StringData& r, int l) { const bool needRep = ((c != ErrorCodes::OK) || !r.empty() || (l != 0)); return needRep ? new ErrorInfo(c, r, l) : NULL; } Status::Status(ErrorCodes::Error code, const std::string& reason, int location) : _error(ErrorInfo::create(code, reason, location)) { ref(_error); } Status::Status(ErrorCodes::Error code, const char* reason, int location) : _error(ErrorInfo::create(code, reason, location)) { ref(_error); } bool Status::compare(const Status& other) const { return code() == other.code() && location() == other.location(); } bool Status::operator==(const Status& other) const { return compare(other); } bool Status::operator!=(const Status& other) const { return !compare(other); } bool Status::compareCode(const ErrorCodes::Error other) const { return code() == other; } bool Status::operator==(const ErrorCodes::Error other) const { return compareCode(other); } bool Status::operator!=(const ErrorCodes::Error other) const { return !compareCode(other); } std::ostream& operator<<(std::ostream& os, const Status& status) { return os << status.codeString() << " " << status.reason(); } std::ostream& operator<<(std::ostream& os, ErrorCodes::Error code) { return os << ErrorCodes::errorString(code); } std::string Status::toString() const { std::ostringstream ss; ss << codeString(); if (!isOK()) ss << " " << reason(); if (location() != 0) ss << " @ " << location(); return ss.str(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/status.h000066400000000000000000000112611273231111400224750ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/error_codes.h" #include "mongo/client/export_macros.h" #include "mongo/platform/atomic_word.h" namespace mongo { /** * Status represents an error state or the absence thereof. * * A Status uses the standardized error codes -- from file 'error_codes.h' -- to * determine an error's cause. It further clarifies the error with a textual * description. Optionally, a Status may also have an error location number, which * should be a unique, grep-able point in the code base (including assert numbers). * * Example usage: * * Status sumAB(int a, int b, int* c) { * if (overflowIfSum(a,b)) { * return Status(ErrorCodes::ERROR_OVERFLOW, "overflow in sumAB", 16494); * } * * *c = a+b; * return Status::OK(); * } * * TODO: expand base/error_codes.h to capture common errors in current code * TODO: generate base/error_codes.h out of a description file * TODO: check 'location' duplicates against assert numbers */ class MONGO_CLIENT_API Status { public: // Short-hand for returning an OK status. static inline Status MONGO_CLIENT_FUNC OK(); /** * Builds an error status given the error code, a textual description of what * caused the error, and a unique position in the where the error occurred * (similar to an assert number) */ Status(ErrorCodes::Error code, const std::string& reason, int location = 0); Status(ErrorCodes::Error code, const char* reason, int location = 0); inline Status(const Status& other); inline Status& operator=(const Status& other); #if __cplusplus >= 201103L inline Status(Status&& other) noexcept; inline Status& operator=(Status&& other) noexcept; #endif // __cplusplus >= 201103L inline ~Status(); /** * Returns true if 'other's error code and location are equal/different to this * instance's. Otherwise returns false. */ bool compare(const Status& other) const; bool operator==(const Status& other) const; bool operator!=(const Status& other) const; /** * Returns true if 'other's error code is equal/different to this instance's. * Otherwise returns false. */ bool compareCode(const ErrorCodes::Error other) const; bool operator==(const ErrorCodes::Error other) const; bool operator!=(const ErrorCodes::Error other) const; // // accessors // inline bool isOK() const; inline ErrorCodes::Error code() const; inline std::string codeString() const; inline std::string reason() const; inline int location() const; std::string toString() const; // // Below interface used for testing code only. // inline AtomicUInt32::WordType refCount() const; private: inline Status(); struct ErrorInfo { AtomicUInt32 refs; // reference counter const ErrorCodes::Error code; // error code const std::string reason; // description of error cause const int location; // unique location of the triggering line in the code static ErrorInfo* create(ErrorCodes::Error code, const StringData& reason, int location); ErrorInfo(ErrorCodes::Error code, const StringData& reason, int location); }; ErrorInfo* _error; /** * Increment/Decrement the reference counter inside an ErrorInfo * * @param error ErrorInfo to be incremented */ static inline void MONGO_CLIENT_FUNC ref(ErrorInfo* error); static inline void MONGO_CLIENT_FUNC unref(ErrorInfo* error); }; MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator==(const ErrorCodes::Error lhs, const Status& rhs); MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator!=(const ErrorCodes::Error lhs, const Status& rhs); // // Convenience method for unittest code. Please use accessors otherwise. // MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& os, const Status& status); MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& os, ErrorCodes::Error); } // namespace mongo #include "mongo/base/status-inl.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/base/status_with.h000066400000000000000000000042271273231111400235340ustar00rootroot00000000000000// status_with.h /* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" namespace mongo { /* * StatusWith is used to return an error or a value * this is designed to make exception code free cleaner by not needing as many out paramters * example: StatusWith fib( int n ) { if ( n < 0 ) return StatusWith( ErrorCodes::BadValue, "paramter to fib has to be >= 0" ); if ( n <= 1 ) return StatusWith( 1 ); StatusWith a = fib( n - 1 ); StatusWith b = fib( n - 2 ); if ( !a.isOK() ) return a; if ( !b.isOK() ) return b; return StatusWith( a.getValue() + b.getValue() ); } * Note: the value is copied in the current implementation, so should be small (int, int*) * not a vector */ template class StatusWith { public: /** * for the error case */ StatusWith(ErrorCodes::Error code, const std::string& reason, int location = 0) : _status(Status(code, reason, location)) {} /** * for the error case */ explicit StatusWith(const Status& status) : _status(status) { // verify(( !status.isOK() ); // TODO } /** * for the OK case */ explicit StatusWith(const T& t) : _status(Status::OK()), _t(t) {} const T& getValue() const { /* verify( isOK() ); */ return _t; } // TODO const Status& getStatus() const { return _status; } bool isOK() const { return _status.isOK(); } std::string toString() const { return _status.toString(); } private: Status _status; T _t; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/base/string_data-inl.h000066400000000000000000000065171273231111400242410ustar00rootroot00000000000000// string_data_inline.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // this should never be included directly #include namespace mongo { inline int StringData::compare(const StringData& other) const { int res = memcmp(_data, other._data, std::min(_size, other._size)); if (res != 0) { return res > 0 ? 1 : -1; } else if (_size == other._size) { return 0; } else { return _size > other._size ? 1 : -1; } } inline bool StringData::equalCaseInsensitive(const StringData& other) const { if (other.size() != size()) return false; for (size_t x = 0; x < size(); x++) { char a = _data[x]; char b = other._data[x]; if (a == b) continue; if (tolower(a) == tolower(b)) continue; return false; } return true; } inline void StringData::copyTo(char* dest, bool includeEndingNull) const { memcpy(dest, _data, size()); if (includeEndingNull) dest[size()] = 0; } inline size_t StringData::find(char c, size_t fromPos) const { if (fromPos >= size()) return std::string::npos; const void* x = memchr(_data + fromPos, c, _size - fromPos); if (x == 0) return std::string::npos; return static_cast(static_cast(x) - _data); } inline size_t StringData::find(const StringData& needle) const { size_t mx = size(); size_t needleSize = needle.size(); if (needleSize == 0) return 0; else if (needleSize > mx) return std::string::npos; mx -= needleSize; for (size_t i = 0; i <= mx; i++) { if (memcmp(_data + i, needle._data, needleSize) == 0) return i; } return std::string::npos; } inline size_t StringData::rfind(char c, size_t fromPos) const { const size_t sz = size(); if (fromPos > sz) fromPos = sz; for (const char* cur = _data + fromPos; cur > _data; --cur) { if (*(cur - 1) == c) return (cur - _data) - 1; } return std::string::npos; } inline StringData StringData::substr(size_t pos, size_t n) const { if (pos > size()) throw std::out_of_range("out of range"); // truncate to end of string if (n > size() - pos) n = size() - pos; return StringData(_data + pos, n); } inline bool StringData::startsWith(const StringData& prefix) const { // TODO: Investigate an optimized implementation. return substr(0, prefix.size()) == prefix; } inline bool StringData::endsWith(const StringData& suffix) const { // TODO: Investigate an optimized implementation. const size_t thisSize = size(); const size_t suffixSize = suffix.size(); if (suffixSize > thisSize) return false; return substr(thisSize - suffixSize) == suffix; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/string_data.cpp000066400000000000000000000026451273231111400240120ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/string_data.h" #include #include namespace mongo { namespace { template size_t murmur3(const StringData& str); template <> size_t murmur3<4>(const StringData& str) { uint32_t hash; MurmurHash3_x86_32(str.rawData(), str.size(), 0, &hash); return hash; } template <> size_t murmur3<8>(const StringData& str) { uint64_t hash[2]; MurmurHash3_x64_128(str.rawData(), str.size(), 0, hash); return static_cast(hash[0]); } } // namespace std::ostream& operator<<(std::ostream& stream, const StringData& value) { return stream.write(value.rawData(), value.size()); } size_t StringData::Hasher::operator()(const StringData& str) const { return murmur3(str); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/base/string_data.h000066400000000000000000000130501273231111400234470ustar00rootroot00000000000000// string_data.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include // for min #include #include #include #include #include "mongo/client/export_macros.h" namespace mongo { /** * A StringData object wraps a 'const string&' or a 'const char*' without copying its * contents. The most common usage is as a function argument that takes any of the two * forms of strings above. Fundamentally, this class tries go around the fact that string * literals in C++ are char[N]'s. * * Notes: * * + The object StringData wraps around must be alive while the StringData is. * * + Because string data can be used to pass a substring around, one should never assume a * rawData() terminates with a null. */ class MONGO_CLIENT_API StringData { public: /** Constructs an empty string data */ StringData() : _data(NULL), _size(0) {} /** * Constructs a StringData, for the case where the length of string is not known. 'c' * must be a pointer to a null-terminated string. */ StringData(const char* str) : _data(str), _size((str == NULL) ? 0 : std::strlen(str)) {} /** * Constructs a StringData explicitly, for the case where the length of the string is * already known. 'c' must be a pointer to a null-terminated string, and len must * be the length that strlen(c) would return, a.k.a the index of the terminator in c. */ StringData(const char* c, size_t len) : _data(c), _size(len) {} /** Constructs a StringData, for the case of a string. */ StringData(const std::string& s) : _data(s.c_str()), _size(s.size()) {} /** * Constructs a StringData explicitly, for the case of a literal whose size is known at * compile time. */ struct LiteralTag {}; template StringData(const char(&val)[N], LiteralTag) : _data(&val[0]), _size(N - 1) {} /** * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'other' in * lexicographical order. */ int compare(const StringData& other) const; /** * note: this uses tolower, and therefore does not handle * come languages correctly. * should be use sparingly */ bool equalCaseInsensitive(const StringData& other) const; void copyTo(char* dest, bool includeEndingNull) const; StringData substr(size_t pos, size_t n = std::numeric_limits::max()) const; // // finders // size_t find(char c, size_t fromPos = 0) const; size_t find(const StringData& needle) const; size_t rfind(char c, size_t fromPos = std::string::npos) const; /** * Returns true if 'prefix' is a substring of this instance, anchored at position 0. */ bool startsWith(const StringData& prefix) const; /** * Returns true if 'suffix' is a substring of this instance, anchored at the end. */ bool endsWith(const StringData& suffix) const; // // accessors // /** * Get the pointer to the first byte of StringData. This is not guaranteed to be * null-terminated, so if using this without checking size(), you are likely doing * something wrong. */ const char* rawData() const { return _data; } size_t size() const { return _size; } bool empty() const { return size() == 0; } std::string toString() const { return std::string(_data, size()); } char operator[](unsigned pos) const { return _data[pos]; } /** * Functor compatible with std::hash for std::unordered_{map,set} * Warning: The hash function is subject to change. Do not use in cases where hashes need * to be consistent across versions. */ struct Hasher { size_t operator()(const StringData& str) const; }; // // iterators // typedef const char* const_iterator; const_iterator begin() const { return rawData(); } const_iterator end() const { return rawData() + size(); } private: const char* _data; // is not guaranted to be null terminated (see "notes" above) size_t _size; // 'size' does not include the null terminator }; inline bool operator==(const StringData& lhs, const StringData& rhs) { return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); } inline bool operator!=(const StringData& lhs, const StringData& rhs) { return !(lhs == rhs); } inline bool operator<(const StringData& lhs, const StringData& rhs) { return lhs.compare(rhs) < 0; } inline bool operator<=(const StringData& lhs, const StringData& rhs) { return lhs.compare(rhs) <= 0; } inline bool operator>(const StringData& lhs, const StringData& rhs) { return lhs.compare(rhs) > 0; } inline bool operator>=(const StringData& lhs, const StringData& rhs) { return lhs.compare(rhs) >= 0; } MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& stream, const StringData& value); } // namespace mongo #include "mongo/base/string_data-inl.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/000077500000000000000000000000001273231111400210275ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson-inl.h000066400000000000000000000022401273231111400227170ustar00rootroot00000000000000/** @file bsoninlines.h a goal here is that the most common bson methods can be used inline-only, a la boost. thus some things are inline that wouldn't necessarily be otherwise. */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { template inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(T value) { _builder->append(_fieldName, value); _fieldName = StringData(); return *_builder; } template inline BSONObjBuilder& Labeler::operator<<(T value) { s_->subobj()->append(l_.l_, value); return *s_->_builder; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson.h000066400000000000000000000051771273231111400221530ustar00rootroot00000000000000/** @file bson.h Main bson include file for mongodb c++ clients. MongoDB includes ../db/jsobj.h instead. This file, however, pulls in much less code / dependencies. @see bsondemo */ /* * Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Main include file for C++ BSON. This pulls in fewer dependencies than mongo/client/dbclient.h, but still requires libmongoclient to link. "BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be represented in JSON (plus a few extensions useful for databases & other languages). http://www.bsonspec.org/ */ #pragma once #ifdef MONGO_EXPOSE_MACROS #error bson.h is for C++ driver consumer use only #endif // Consumers of the MongoDB C++ client library must define STATIC_LIBMONGOCLIENT when including // this header if they intend to link against the static version of the library. This is best // handled by adding STATIC_LIBMONGOCLIENT to the list of definitions passed on each compile // invocation. #ifndef STATIC_LIBMONGOCLIENT #if defined(_WIN32) && !defined(_DLL) #error "The DLL build of libmongoclient requires consuming code to be built with /MD or /MDd" #endif #endif #if defined(_MSC_VER) #pragma warning(push) // Don't emit deprecation warnings #pragma warning(disable : 4996) #if defined(_DLL) // Don't spam DLL consumers with warnings about STL symbol exports #pragma warning(disable : 4251) #pragma warning(disable : 4275) #endif #endif #if defined(_WIN32) && !defined(_WINSOCK2API_) #error "You must include the windows and windows sockets headers before bson.h" #endif #include "mongo/config.h" #include "mongo/client/redef_macros.h" #include "mongo/client/autolib.h" #include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/bsonobjiterator.h" #include "mongo/bson/bsontypes.h" #include "mongo/bson/bson-inl.h" #include "mongo/bson/oid.h" #include "mongo/bson/util/builder.h" #include "mongo/client/undef_macros.h" #if defined(_MSC_VER) && defined(_DLL) #pragma warning(pop) #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_db.h000066400000000000000000000037051273231111400226130ustar00rootroot00000000000000/** @file bson_db.h */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* This file contains the implementation of BSON-related methods that are required by the MongoDB database server. Normally, for standalone BSON usage, you do not want this file - it will tend to pull in some other files from the MongoDB project. Thus, bson.h (the main file one would use) does not include this file. */ #pragma once #include "mongo/util/time_support.h" namespace mongo { inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const DateNowLabeler& id) { _builder->appendDate(_fieldName, jsTime()); _fieldName = StringData(); return *_builder; } inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const NullLabeler& id) { _builder->appendNull(_fieldName); _fieldName = StringData(); return *_builder; } inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const UndefinedLabeler& id) { _builder->appendUndefined(_fieldName); _fieldName = StringData(); return *_builder; } inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MinKeyLabeler& id) { _builder->appendMinKey(_fieldName); _fieldName = StringData(); return *_builder; } inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MaxKeyLabeler& id) { _builder->appendMaxKey(_fieldName); _fieldName = StringData(); return *_builder; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_field.h000066400000000000000000000062431273231111400233110ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/bson/bsonobj.h" namespace mongo { /** * A BSONField holds the name and the type intended for a given BSON element. The * class helps documenting and enforcing that field's type. * * Example usages: * * In a header file: * // Determines the types for the fields used in a collection. * static const string MyColl; * struct MyCollFields { * static BSONField name; * static BSONField draining; * static BSONField count; * }; * * In a cpp file: * const string MyColl = "my_collection_name"; * * // determines the names used for the fields * BSONField MyCollFields::name("_id"); * BSONField MyCollFields::draining("draining"); * BSONField MyCollFields::count("count"); * * In an insert: * conn->insert(myColl, * BSON(MyCollFields::name("id_for_this_doc") << * MyCollFields::draining(true) << * MyCollFields::count(0))); * * In a query: * conn->findOne(myColl, BSON(MyCollFields::count.gt(10))) ; * */ template class BSONFieldValue { public: BSONFieldValue(const std::string& name, const T& t) : _name(name), _t(t) {} const T& value() const { return _t; } const std::string& name() const { return _name; } private: std::string _name; T _t; }; template class BSONField { public: BSONField(const std::string& name) : _name(name), _defaultSet(false) {} BSONField(const std::string& name, const T& defaultVal) : _name(name), _default(defaultVal), _defaultSet(true) {} BSONFieldValue make(const T& t) const { return BSONFieldValue(_name, t); } BSONFieldValue operator()(const T& t) const { return BSONFieldValue(_name, t); } const std::string& name() const { return _name; } const T& getDefault() const { return _default; } bool hasDefault() const { return _defaultSet; } std::string operator()() const { return _name; } BSONFieldValue query(const char* q, const T& t) const; BSONFieldValue gt(const T& t) const { return query("$gt", t); } BSONFieldValue lt(const T& t) const { return query("$lt", t); } BSONFieldValue ne(const T& t) const { return query("$ne", t); } private: std::string _name; T _default; bool _defaultSet; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_field_test.cpp000066400000000000000000000026061273231111400247020ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/db/jsobj.h" #include "mongo/unittest/unittest.h" namespace { using mongo::BSONField; using mongo::BSONObj; TEST(Assignment, Simple) { BSONField x("x"); BSONObj o = BSON(x << 5); ASSERT_EQUALS(BSON("x" << 5), o); } TEST(Make, Simple) { BSONField x("x"); BSONObj o = BSON(x.make(5)); ASSERT_EQUALS(BSON("x" << 5), o); } TEST(Query, GreaterThan) { BSONField x("x"); BSONObj o = BSON(x(5)); ASSERT_EQUALS(BSON("x" << 5), o); o = BSON(x.gt(5)); ASSERT_EQUALS(BSON("x" << BSON("$gt" << 5)), o); } TEST(Query, NotEqual) { BSONField x("x"); BSONObj o = BSON(x(10)); ASSERT_EQUALS(BSON("x" << 10), o); o = BSON(x.ne(5)); ASSERT_EQUALS(BSON("x" << BSON("$ne" << 5)), o); } } // unnamed namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_obj_test.cpp000066400000000000000000000171641273231111400243760ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/unittest/unittest.h" namespace { TEST(BSONObjToString, EmptyArray) { const char text[] = "{ x: [] }"; mongo::BSONObj o1 = mongo::fromjson(text); const std::string o1_str = o1.toString(); ASSERT_EQUALS(text, o1_str); } TEST(BSONObjCompare, NumberDouble) { ASSERT_LT(BSON("" << 0.0), BSON("" << 1.0)); ASSERT_LT(BSON("" << -1.0), BSON("" << 0.0)); ASSERT_LT(BSON("" << -1.0), BSON("" << 1.0)); ASSERT_LT(BSON("" << 0.0), BSON("" << 0.1)); ASSERT_LT(BSON("" << 0.1), BSON("" << 1.0)); ASSERT_LT(BSON("" << -1.0), BSON("" << -0.1)); ASSERT_LT(BSON("" << -0.1), BSON("" << 0.0)); ASSERT_LT(BSON("" << -0.1), BSON("" << 0.1)); ASSERT_LT(BSON("" << 0.0), BSON("" << std::numeric_limits::denorm_min())); ASSERT_GT(BSON("" << 0.0), BSON("" << -std::numeric_limits::denorm_min())); ASSERT_LT(BSON("" << 1.0), BSON("" << (1.0 + std::numeric_limits::epsilon()))); ASSERT_GT(BSON("" << -1.0), BSON("" << (-1.0 - std::numeric_limits::epsilon()))); ASSERT_EQ(BSON("" << 0.0), BSON("" << -0.0)); ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << 0.0)); ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << std::numeric_limits::max())); // max is finite ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << -std::numeric_limits::infinity())); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << 0.0)); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << -std::numeric_limits::max())); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << std::numeric_limits::infinity())); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << 0.0)); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << -std::numeric_limits::max())); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << std::numeric_limits::infinity())); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << -std::numeric_limits::infinity())); // TODO in C++11 use hex floating point to test distinct NaN representations ASSERT_EQ(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << std::numeric_limits::signaling_NaN())); } TEST(BSONObjCompare, NumberLong_Double) { ASSERT_EQ(BSON("" << 0ll), BSON("" << 0.0)); ASSERT_EQ(BSON("" << 0ll), BSON("" << -0.0)); ASSERT_EQ(BSON("" << 1ll), BSON("" << 1.0)); ASSERT_EQ(BSON("" << -1ll), BSON("" << -1.0)); ASSERT_LT(BSON("" << 0ll), BSON("" << 1.0)); ASSERT_LT(BSON("" << -1ll), BSON("" << 0.0)); ASSERT_LT(BSON("" << -1ll), BSON("" << 1.0)); ASSERT_LT(BSON("" << 0ll), BSON("" << 0.1)); ASSERT_LT(BSON("" << 0.1), BSON("" << 1ll)); ASSERT_LT(BSON("" << -1ll), BSON("" << -0.1)); ASSERT_LT(BSON("" << -0.1), BSON("" << 0ll)); ASSERT_LT(BSON("" << 0ll), BSON("" << std::numeric_limits::denorm_min())); ASSERT_GT(BSON("" << 0ll), BSON("" << -std::numeric_limits::denorm_min())); ASSERT_LT(BSON("" << 1ll), BSON("" << (1.0 + std::numeric_limits::epsilon()))); ASSERT_GT(BSON("" << -1ll), BSON("" << (-1.0 - std::numeric_limits::epsilon()))); ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << 0ll)); ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << std::numeric_limits::max())); ASSERT_GT(BSON("" << std::numeric_limits::infinity()), BSON("" << std::numeric_limits::min())); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << 0ll)); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << std::numeric_limits::max())); ASSERT_LT(BSON("" << -std::numeric_limits::infinity()), BSON("" << std::numeric_limits::min())); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << 0ll)); ASSERT_LT(BSON("" << std::numeric_limits::quiet_NaN()), BSON("" << std::numeric_limits::min())); for (int powerOfTwo = 0; powerOfTwo < 63; powerOfTwo++) { const long long lNum = 1ll << powerOfTwo; const double dNum = double(lNum); // All powers of two in this range can be represented exactly as doubles. invariant(lNum == static_cast(dNum)); ASSERT_EQ(BSON("" << lNum), BSON("" << dNum)); ASSERT_EQ(BSON("" << -lNum), BSON("" << -dNum)); ASSERT_GT(BSON("" << (lNum + 1)), BSON("" << dNum)); ASSERT_LT(BSON("" << (lNum - 1)), BSON("" << dNum)); ASSERT_GT(BSON("" << (-lNum + 1)), BSON("" << -dNum)); ASSERT_LT(BSON("" << (-lNum - 1)), BSON("" << -dNum)); if (powerOfTwo <= 52) { // is dNum - 0.5 representable? ASSERT_GT(BSON("" << lNum), BSON("" << (dNum - 0.5))); ASSERT_LT(BSON("" << -lNum), BSON("" << -(dNum - 0.5))); } if (powerOfTwo <= 51) { // is dNum + 0.5 representable? ASSERT_LT(BSON("" << lNum), BSON("" << (dNum + 0.5))); ASSERT_GT(BSON("" << -lNum), BSON("" << -(dNum + 0.5))); } } { // Numbers around +/- numeric_limits::max() which can't be represented // precisely as a double. const long long maxLL = std::numeric_limits::max(); const double closestAbove = 9223372036854775808.0; // 2**63 const double closestBelow = 9223372036854774784.0; // 2**63 - epsilon ASSERT_GT(BSON("" << maxLL), BSON("" << (maxLL - 1))); ASSERT_LT(BSON("" << maxLL), BSON("" << closestAbove)); ASSERT_GT(BSON("" << maxLL), BSON("" << closestBelow)); ASSERT_LT(BSON("" << -maxLL), BSON("" << -(maxLL - 1))); ASSERT_GT(BSON("" << -maxLL), BSON("" << -closestAbove)); ASSERT_LT(BSON("" << -maxLL), BSON("" << -closestBelow)); } { // Numbers around numeric_limits::min() which can be represented precisely as // a double, but not as a positive long long. const long long minLL = std::numeric_limits::min(); const double closestBelow = -9223372036854777856.0; // -2**63 - epsilon const double equal = -9223372036854775808.0; // 2**63 const double closestAbove = -9223372036854774784.0; // -2**63 + epsilon invariant(static_cast(minLL) == equal); invariant(static_cast(equal) == minLL); ASSERT_LT(BSON("" << minLL), BSON("" << (minLL + 1))); ASSERT_EQ(BSON("" << minLL), BSON("" << equal)); ASSERT_LT(BSON("" << minLL), BSON("" << closestAbove)); ASSERT_GT(BSON("" << minLL), BSON("" << closestBelow)); } } } // unnamed namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_validate.cpp000066400000000000000000000264021273231111400243510ustar00rootroot00000000000000// bson_validate.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "mongo/base/data_view.h" #include "mongo/bson/bson_validate.h" #include "mongo/bson/oid.h" #include "mongo/db/jsobj.h" namespace mongo { namespace { /** * Creates a status with InvalidBSON code and adds information about _id if available. * WARNING: only pass in a non-EOO idElem if it has been fully validated already! */ Status makeError(std::string baseMsg, BSONElement idElem) { if (idElem.eoo()) { baseMsg += " in object with unknown _id"; } else { baseMsg += " in object with " + idElem.toString(/*field name=*/true, /*full=*/true); } return Status(ErrorCodes::InvalidBSON, baseMsg); } class Buffer { public: Buffer(const char* buffer, uint64_t maxLength) : _buffer(buffer), _position(0), _maxLength(maxLength) {} template bool readNumber(N* out) { if ((_position + sizeof(N)) > _maxLength) return false; if (out) { *out = ConstDataView(_buffer).readLE(_position); } _position += sizeof(N); return true; } Status readCString(StringData* out) { const void* x = memchr(_buffer + _position, 0, _maxLength - _position); if (!x) return makeError("no end of c-string", _idElem); uint64_t len = static_cast(static_cast(x) - (_buffer + _position)); StringData data(_buffer + _position, len); _position += len + 1; if (out) { *out = data; } return Status::OK(); } Status readUTF8String(StringData* out) { int sz; if (!readNumber(&sz)) return makeError("invalid bson", _idElem); if (sz <= 0) { // must have NULL at the very least return makeError("invalid bson", _idElem); } if (out) { *out = StringData(_buffer + _position, sz); } if (!skip(sz - 1)) return makeError("invalid bson", _idElem); char c; if (!readNumber(&c)) return makeError("invalid bson", _idElem); if (c != 0) return makeError("not null terminated string", _idElem); return Status::OK(); } bool skip(uint64_t sz) { _position += sz; return _position < _maxLength; } uint64_t position() const { return _position; } const char* getBasePtr() const { return _buffer; } /** * WARNING: only pass in a non-EOO idElem if it has been fully validated already! */ void setIdElem(BSONElement idElem) { _idElem = idElem; } private: const char* _buffer; uint64_t _position; uint64_t _maxLength; BSONElement _idElem; }; struct ValidationState { enum State { BeginObj = 1, WithinObj, EndObj, BeginCodeWScope, EndCodeWScope, Done }; }; class ValidationObjectFrame { public: int startPosition() const { return _startPosition & ~(1 << 31); } bool isCodeWithScope() const { return _startPosition & (1 << 31); } void setStartPosition(int pos) { _startPosition = (_startPosition & (1 << 31)) | (pos & ~(1 << 31)); } void setIsCodeWithScope(bool isCodeWithScope) { if (isCodeWithScope) { _startPosition |= 1 << 31; } else { _startPosition &= ~(1 << 31); } } int expectedSize; private: int _startPosition; }; /** * WARNING: only pass in a non-EOO idElem if it has been fully validated already! */ Status validateElementInfo(Buffer* buffer, ValidationState::State* nextState, BSONElement idElem) { Status status = Status::OK(); signed char type; if (!buffer->readNumber(&type)) return makeError("invalid bson", idElem); if (type == EOO) { *nextState = ValidationState::EndObj; return Status::OK(); } StringData name; status = buffer->readCString(&name); if (!status.isOK()) return status; switch (type) { case MinKey: case MaxKey: case jstNULL: case Undefined: return Status::OK(); case jstOID: if (!buffer->skip(OID::kOIDSize)) return makeError("invalid bson", idElem); return Status::OK(); case NumberInt: if (!buffer->skip(sizeof(int32_t))) return makeError("invalid bson", idElem); return Status::OK(); case Bool: if (!buffer->skip(sizeof(int8_t))) return makeError("invalid bson", idElem); return Status::OK(); case NumberDouble: case NumberLong: case Timestamp: case Date: if (!buffer->skip(sizeof(int64_t))) return makeError("invalid bson", idElem); return Status::OK(); case DBRef: status = buffer->readUTF8String(NULL); if (!status.isOK()) return status; buffer->skip(OID::kOIDSize); return Status::OK(); case RegEx: status = buffer->readCString(NULL); if (!status.isOK()) return status; status = buffer->readCString(NULL); if (!status.isOK()) return status; return Status::OK(); case Code: case Symbol: case String: status = buffer->readUTF8String(NULL); if (!status.isOK()) return status; return Status::OK(); case BinData: { int sz; if (!buffer->readNumber(&sz)) return makeError("invalid bson", idElem); if (sz < 0 || sz == std::numeric_limits::max()) return makeError("invalid size in bson", idElem); if (!buffer->skip(1 + sz)) return makeError("invalid bson", idElem); return Status::OK(); } case CodeWScope: *nextState = ValidationState::BeginCodeWScope; return Status::OK(); case Object: case Array: *nextState = ValidationState::BeginObj; return Status::OK(); default: return makeError("invalid bson type", idElem); } } Status validateBSONIterative(Buffer* buffer) { std::deque frames; ValidationObjectFrame* curr = NULL; ValidationState::State state = ValidationState::BeginObj; uint64_t idElemStartPos = 0; // will become idElem once validated BSONElement idElem; while (state != ValidationState::Done) { switch (state) { case ValidationState::BeginObj: frames.push_back(ValidationObjectFrame()); curr = &frames.back(); curr->setStartPosition(buffer->position()); curr->setIsCodeWithScope(false); if (!buffer->readNumber(&curr->expectedSize)) { return makeError("bson size is larger than buffer size", idElem); } state = ValidationState::WithinObj; // fall through case ValidationState::WithinObj: { const bool atTopLevel = frames.size() == 1; // check if we've finished validating idElem and are at start of next element. if (atTopLevel && idElemStartPos) { idElem = BSONElement(buffer->getBasePtr() + idElemStartPos); buffer->setIdElem(idElem); idElemStartPos = 0; } const uint64_t elemStartPos = buffer->position(); ValidationState::State nextState = state; Status status = validateElementInfo(buffer, &nextState, idElem); if (!status.isOK()) return status; // we've already validated that fieldname is safe to access as long as we aren't // at the end of the object, since EOO doesn't have a fieldname. if (nextState != ValidationState::EndObj && idElem.eoo() && atTopLevel) { if (strcmp(buffer->getBasePtr() + elemStartPos + 1 /*type*/, "_id") == 0) { idElemStartPos = elemStartPos; } } state = nextState; break; } case ValidationState::EndObj: { int actualLength = buffer->position() - curr->startPosition(); if (actualLength != curr->expectedSize) { return makeError("bson length doesn't match what we found", idElem); } frames.pop_back(); if (frames.empty()) { state = ValidationState::Done; } else { curr = &frames.back(); if (curr->isCodeWithScope()) state = ValidationState::EndCodeWScope; else state = ValidationState::WithinObj; } break; } case ValidationState::BeginCodeWScope: { frames.push_back(ValidationObjectFrame()); curr = &frames.back(); curr->setStartPosition(buffer->position()); curr->setIsCodeWithScope(true); if (!buffer->readNumber(&curr->expectedSize)) return makeError("invalid bson CodeWScope size", idElem); Status status = buffer->readUTF8String(NULL); if (!status.isOK()) return status; state = ValidationState::BeginObj; break; } case ValidationState::EndCodeWScope: { int actualLength = buffer->position() - curr->startPosition(); if (actualLength != curr->expectedSize) { return makeError("bson length for CodeWScope doesn't match what we found", idElem); } frames.pop_back(); if (frames.empty()) return makeError("unnested CodeWScope", idElem); curr = &frames.back(); state = ValidationState::WithinObj; break; } case ValidationState::Done: break; } } return Status::OK(); } } // namespace Status validateBSON(const char* originalBuffer, uint64_t maxLength) { if (maxLength < 5) { return Status(ErrorCodes::InvalidBSON, "bson data has to be at least 5 bytes"); } Buffer buf(originalBuffer, maxLength); return validateBSONIterative(&buf); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_validate.h000066400000000000000000000021251273231111400240120ustar00rootroot00000000000000// bson_Validate.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/bson/bsontypes.h" #include "mongo/client/export_macros.h" #include "mongo/platform/cstdint.h" namespace mongo { /** * @param buf - bson data * @param maxLength - maxLength of buffer * this is NOT the bson size, but how far we know the buffer is valid */ MONGO_CLIENT_API Status MONGO_CLIENT_FUNC validateBSON(const char* buf, uint64_t maxLength); } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bson_validate_test.cpp000066400000000000000000000225041273231111400254070ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include #include "mongo/base/data_view.h" #include "mongo/db/jsobj.h" #include "mongo/unittest/unittest.h" #include "mongo/platform/random.h" #include "mongo/bson/bson_validate.h" #include "mongo/util/log.h" namespace { using std::endl; using namespace mongo; void appendInvalidStringElement(const char* fieldName, BufBuilder* bb) { // like a BSONObj string, but without a NUL terminator. bb->appendChar(String); bb->appendStr(fieldName, /*withNUL*/ true); bb->appendNum(4); bb->appendStr("asdf", /*withNUL*/ false); } TEST(BSONValidate, Basic) { BSONObj x; ASSERT_TRUE(x.valid()); x = BSON("x" << 1); ASSERT_TRUE(x.valid()); } TEST(BSONValidate, RandomData) { PseudoRandom r(17); int numValid = 0; int numToRun = 1000; long long jsonSize = 0; for (int i = 0; i < numToRun; i++) { int size = 1234; char* x = new char[size]; DataView(x).writeLE(size); for (int i = 4; i < size; i++) { x[i] = r.nextInt32(255); } x[size - 1] = 0; BSONObj o(x); ASSERT_EQUALS(size, o.objsize()); if (o.valid()) { numValid++; jsonSize += o.jsonString().size(); ASSERT_OK(validateBSON(o.objdata(), o.objsize())); } else { ASSERT_NOT_OK(validateBSON(o.objdata(), o.objsize())); } delete[] x; } log() << "RandomData: didn't crash valid/total: " << numValid << "/" << numToRun << " (want few valid ones)" << " jsonSize: " << jsonSize << endl; } TEST(BSONValidate, MuckingData1) { BSONObj theObject; { BSONObjBuilder b; b.append("name", "eliot was here"); b.append("yippee", "asd"); BSONArrayBuilder a(b.subarrayStart("arr")); for (int i = 0; i < 100; i++) { a.append(BSON("x" << i << "who" << "me" << "asd" << "asd")); } a.done(); b.done(); theObject = b.obj(); } int numValid = 0; int numToRun = 1000; long long jsonSize = 0; for (int i = 4; i < theObject.objsize() - 1; i++) { BSONObj mine = theObject.copy(); unsigned char* data = reinterpret_cast(const_cast(mine.objdata())); data[i] = 200; numToRun++; if (mine.valid()) { numValid++; jsonSize += mine.jsonString().size(); ASSERT_OK(validateBSON(mine.objdata(), mine.objsize())); } else { ASSERT_NOT_OK(validateBSON(mine.objdata(), mine.objsize())); } } log() << "MuckingData1: didn't crash valid/total: " << numValid << "/" << numToRun << " (want few valid ones) " << " jsonSize: " << jsonSize << endl; } TEST(BSONValidate, Fuzz) { int64_t seed = time(0); log() << "BSONValidate Fuzz random seed: " << seed << endl; PseudoRandom randomSource(seed); BSONObj original = BSON("one" << 3 << "two" << 5 << "three" << BSONObj() << "four" << BSON("five" << BSON("six" << 11)) << "seven" << BSON_ARRAY("a" << "bb" << "ccc" << 5) << "eight" << BSONDBRef("rrr", OID("01234567890123456789aaaa")) << "_id" << OID("deadbeefdeadbeefdeadbeef") << "nine" << BSONBinData("\x69\xb7", 2, BinDataGeneral) << "ten" << Date_t(44) << "eleven" << BSONRegEx("foooooo", "i")); int32_t fuzzFrequencies[] = {2, 10, 20, 100, 1000}; for (size_t i = 0; i < sizeof(fuzzFrequencies) / sizeof(int32_t); ++i) { int32_t fuzzFrequency = fuzzFrequencies[i]; // Copy the 'original' BSONObj to 'buffer'. boost::scoped_array buffer(new char[original.objsize()]); memcpy(buffer.get(), original.objdata(), original.objsize()); // Randomly flip bits in 'buffer', with probability determined by 'fuzzFrequency'. The // first four bytes, representing the size of the object, are excluded from bit // flipping. for (int32_t byteIdx = 4; byteIdx < original.objsize(); ++byteIdx) { for (int32_t bitIdx = 0; bitIdx < 8; ++bitIdx) { if (randomSource.nextInt32(fuzzFrequency) == 0) { reinterpret_cast(buffer[byteIdx]) ^= (1U << bitIdx); } } } BSONObj fuzzed(buffer.get()); // Check that the two validation implementations agree (and neither crashes). ASSERT_EQUALS(fuzzed.valid(), validateBSON(fuzzed.objdata(), fuzzed.objsize()).isOK()); } } TEST(BSONValidateFast, Empty) { BSONObj x; ASSERT_OK(validateBSON(x.objdata(), x.objsize())); } TEST(BSONValidateFast, RegEx) { BSONObjBuilder b; b.appendRegex("foo", "i"); BSONObj x = b.obj(); ASSERT_OK(validateBSON(x.objdata(), x.objsize())); } TEST(BSONValidateFast, Simple0) { BSONObj x; ASSERT_OK(validateBSON(x.objdata(), x.objsize())); x = BSON("foo" << 17 << "bar" << "eliot"); ASSERT_OK(validateBSON(x.objdata(), x.objsize())); } TEST(BSONValidateFast, Simple2) { char buf[64]; for (int i = 1; i <= JSTypeMax; i++) { BSONObjBuilder b; sprintf(buf, "foo%d", i); b.appendMinForType(buf, i); sprintf(buf, "bar%d", i); b.appendMaxForType(buf, i); BSONObj x = b.obj(); ASSERT_OK(validateBSON(x.objdata(), x.objsize())); } } TEST(BSONValidateFast, Simple3) { BSONObjBuilder b; char buf[64]; for (int i = 1; i <= JSTypeMax; i++) { sprintf(buf, "foo%d", i); b.appendMinForType(buf, i); sprintf(buf, "bar%d", i); b.appendMaxForType(buf, i); } BSONObj x = b.obj(); ASSERT_OK(validateBSON(x.objdata(), x.objsize())); } TEST(BSONValidateFast, NestedObject) { BSONObj x = BSON("a" << 1 << "b" << BSON("c" << 2 << "d" << BSONArrayBuilder().obj() << "e" << BSON_ARRAY("1" << 2 << 3))); ASSERT_OK(validateBSON(x.objdata(), x.objsize())); ASSERT_NOT_OK(validateBSON(x.objdata(), x.objsize() / 2)); } TEST(BSONValidateFast, ErrorWithId) { BufBuilder bb; BSONObjBuilder ob(bb); ob.append("_id", 1); appendInvalidStringElement("not_id", &bb); const BSONObj x = ob.done(); const Status status = validateBSON(x.objdata(), x.objsize()); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "not null terminated string in object with _id: 1"); } TEST(BSONValidateFast, ErrorBeforeId) { BufBuilder bb; BSONObjBuilder ob(bb); appendInvalidStringElement("not_id", &bb); ob.append("_id", 1); const BSONObj x = ob.done(); const Status status = validateBSON(x.objdata(), x.objsize()); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "not null terminated string in object with unknown _id"); } TEST(BSONValidateFast, ErrorNoId) { BufBuilder bb; BSONObjBuilder ob(bb); appendInvalidStringElement("not_id", &bb); const BSONObj x = ob.done(); const Status status = validateBSON(x.objdata(), x.objsize()); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "not null terminated string in object with unknown _id"); } TEST(BSONValidateFast, ErrorIsInId) { BufBuilder bb; BSONObjBuilder ob(bb); appendInvalidStringElement("_id", &bb); const BSONObj x = ob.done(); const Status status = validateBSON(x.objdata(), x.objsize()); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "not null terminated string in object with unknown _id"); } TEST(BSONValidateFast, NonTopLevelId) { BufBuilder bb; BSONObjBuilder ob(bb); ob.append("not_id1", BSON("_id" << "not the real _id")); appendInvalidStringElement("not_id2", &bb); const BSONObj x = ob.done(); const Status status = validateBSON(x.objdata(), x.objsize()); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "not null terminated string in object with unknown _id"); } TEST(BSONValidateFast, StringHasSomething) { BufBuilder bb; BSONObjBuilder ob(bb); bb.appendChar(String); bb.appendStr("x", /*withNUL*/ true); bb.appendNum(0); const BSONObj x = ob.done(); ASSERT_EQUALS(5 // overhead + 1 // type + 2 // name + 4 // size , x.objsize()); ASSERT_NOT_OK(validateBSON(x.objdata(), x.objsize())); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsondemo/000077500000000000000000000000001273231111400226355ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsondemo/bsondemo.cpp000066400000000000000000000077511273231111400251610ustar00rootroot00000000000000// @file bsondemo.cpp /* * Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Example of use of BSON from C++. Example is solely BSON, no MongoDB involved. Requires boost (headers only). Works as c++ "headers-only" (the parts actually exercised herein that is - some functions require .cpp files). To build and run: # "../../.." is the directory mongo/src/ g++ -o bsondemo -I ../../.. bsondemo.cpp ./bsondemo Windows: project files are available in this directory for bsondemo.cpp for use with Visual Studio. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include using mongo::BSONElement; using mongo::BSONObj; using mongo::BSONObjBuilder; void iter(BSONObj o) { /* iterator example */ std::cout << "\niter()\n"; for (BSONObj::iterator i(o); i.more();) { std::cout << ' ' << i.next().toString() << '\n'; } } int main() { // As of legacy-1.0-rc1-pre, you must initialize the driver in order to use // the BSON library OID class. mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::cout << "build bits: " << 8 * sizeof(char*) << '\n' << std::endl; /* a bson object defaults on construction to { } */ BSONObj empty; std::cout << "empty: " << empty << std::endl; /* make a simple { _id : , when : , name : 'joe', age : 33.7 } object */ { const mongo::OID generated = mongo::OID::gen(); std::cout << "Generated an OID: " << generated << std::endl; BSONObjBuilder b; b.append("_id", generated); b.append("when", mongo::jsTime()); b.append("name", "joe"); b.append("age", 33.7); BSONObj result = b.obj(); std::cout << "json for object with _id: " << result << std::endl; } /* make { name : 'joe', age : 33.7 } with a more compact notation. */ BSONObj x = BSONObjBuilder().append("name", "joe").append("age", 33.7).obj(); /* convert from bson to json */ std::string json = x.toString(); std::cout << "json for x:" << json << std::endl; /* access some fields of bson object x */ std::cout << "Some x things: " << x["name"] << ' ' << x["age"].Number() << ' ' << x.isEmpty() << std::endl; /* make a bit more complex object with some nesting { x : 'asdf', y : true, subobj : { z : 3, q : 4 } } */ BSONObj y = BSON("x" << "asdf" << "y" << true << "subobj" << BSON("z" << 3 << "q" << 4)); /* print it */ std::cout << "y: " << y << std::endl; /* reach in and get subobj.z */ std::cout << "subobj.z: " << y.getFieldDotted("subobj.z").Number() << std::endl; /* alternate syntax: */ std::cout << "subobj.z: " << y["subobj"]["z"].Number() << std::endl; /* fetch all *top level* elements from object y into a vector */ std::vector v; y.elems(v); std::cout << v[0] << std::endl; /* into an array */ std::list L; y.elems(L); BSONObj sub = y["subobj"].Obj(); iter(y); return 0; } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonelement.cpp000066400000000000000000001026261273231111400240550ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/bson/bsonelement.h" #include #include "mongo/base/compare_numbers.h" #include "mongo/base/data_cursor.h" #include "mongo/db/jsobj.h" #include "mongo/util/base64.h" #include "mongo/util/debug_util.h" #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" namespace mongo { using std::dec; using std::hex; using std::numeric_limits; using std::string; using std::stringstream; namespace str = mongoutils::str; // need to move to bson/, but has dependency on base64 so move that to bson/util/ first. string BSONElement::jsonString(JsonStringFormat format, bool includeFieldNames, int pretty) const { int sign; stringstream s; if (includeFieldNames) s << '"' << escape(fieldName()) << "\" : "; switch (type()) { case mongo::String: case Symbol: s << '"' << escape(string(valuestr(), valuestrsize() - 1)) << '"'; break; case NumberLong: if (format == TenGen) { s << "NumberLong(" << _numberLong() << ")"; } else { s << "{ \"$numberLong\" : \"" << _numberLong() << "\" }"; } break; case NumberInt: if (format == JS) { s << "NumberInt(" << _numberInt() << ")"; break; } case NumberDouble: if (number() >= -numeric_limits::max() && number() <= numeric_limits::max()) { s.precision(16); s << number(); } // This is not valid JSON, but according to RFC-4627, "Numeric values that cannot be // represented as sequences of digits (such as Infinity and NaN) are not permitted." so // we are accepting the fact that if we have such values we cannot output valid JSON. else if (mongo::isNaN(number())) { s << "NaN"; } else if (mongo::isInf(number(), &sign)) { s << (sign == 1 ? "Infinity" : "-Infinity"); } else { StringBuilder ss; ss << "Number " << number() << " cannot be represented in JSON"; string message = ss.str(); massert(10311, message.c_str(), false); } break; case mongo::Bool: s << (boolean() ? "true" : "false"); break; case jstNULL: s << "null"; break; case Undefined: if (format == Strict) { s << "{ \"$undefined\" : true }"; } else { s << "undefined"; } break; case Object: s << embeddedObject().jsonString(format, pretty); break; case mongo::Array: { if (embeddedObject().isEmpty()) { s << "[]"; break; } s << "[ "; BSONObjIterator i(embeddedObject()); BSONElement e = i.next(); if (!e.eoo()) { int count = 0; while (1) { if (pretty) { s << '\n'; for (int x = 0; x < pretty; x++) s << " "; } if (strtol(e.fieldName(), 0, 10) > count) { s << "undefined"; } else { s << e.jsonString(format, false, pretty ? pretty + 1 : 0); e = i.next(); } count++; if (e.eoo()) break; s << ", "; } } s << " ]"; break; } case DBRef: { if (format == TenGen) s << "Dbref( "; else s << "{ \"$ref\" : "; s << '"' << valuestr() << "\", "; if (format != TenGen) s << "\"$id\" : "; s << '"' << mongo::OID::from(valuestr() + valuestrsize()) << "\" "; if (format == TenGen) s << ')'; else s << '}'; break; } case jstOID: if (format == TenGen) { s << "ObjectId( "; } else { s << "{ \"$oid\" : "; } s << '"' << __oid() << '"'; if (format == TenGen) { s << " )"; } else { s << " }"; } break; case BinData: { ConstDataCursor reader(value()); const int len = reader.readLEAndAdvance(); BinDataType type = static_cast(reader.readLEAndAdvance()); s << "{ \"$binary\" : \""; base64::encode(s, reader.view(), len); s << "\", \"$type\" : \"" << hex; s.width(2); s.fill('0'); s << type << dec; s << "\" }"; break; } case mongo::Date: if (format == Strict) { Date_t d = date(); s << "{ \"$date\" : "; // The two cases in which we cannot convert Date_t::millis to an ISO Date string are // when the date is too large to format (SERVER-13760), and when the date is before // the epoch (SERVER-11273). Since Date_t internally stores millis as an unsigned // long long, despite the fact that it is logically signed (SERVER-8573), this check // handles both the case where Date_t::millis is too large, and the case where // Date_t::millis is negative (before the epoch). if (d.isFormatable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; } else { s << "{ \"$numberLong\" : \"" << static_cast(d.millis) << "\" }"; } s << " }"; } else { s << "Date( "; if (pretty) { Date_t d = date(); // The two cases in which we cannot convert Date_t::millis to an ISO Date string // are when the date is too large to format (SERVER-13760), and when the date is // before the epoch (SERVER-11273). Since Date_t internally stores millis as an // unsigned long long, despite the fact that it is logically signed // (SERVER-8573), this check handles both the case where Date_t::millis is too // large, and the case where Date_t::millis is negative (before the epoch). if (d.isFormatable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; } else { // FIXME: This is not parseable by the shell, since it may not fit in a // float s << d.millis; } } else { s << date().asInt64(); } s << " )"; } break; case RegEx: if (format == Strict) { s << "{ \"$regex\" : \"" << escape(regex()); s << "\", \"$options\" : \"" << regexFlags() << "\" }"; } else { s << "/" << escape(regex(), true) << "/"; // FIXME Worry about alpha order? for (const char* f = regexFlags(); *f; ++f) { switch (*f) { case 'g': case 'i': case 'm': s << *f; default: break; } } } break; case CodeWScope: { BSONObj scope = codeWScopeObject(); if (!scope.isEmpty()) { s << "{ \"$code\" : \"" << escape(_asCode()) << "\" , " << "\"$scope\" : " << scope.jsonString() << " }"; break; } } case Code: s << "\"" << escape(_asCode()) << "\""; break; case mongo::Timestamp: { Timestamp_t ts = timestamp(); if (format == TenGen) { s << "Timestamp( " << ts.seconds() << ", " << ts.increment() << " )"; } else { s << "{ \"$timestamp\" : { \"t\" : " << ts.seconds() << ", \"i\" : " << ts.increment() << " } }"; } break; } case MinKey: s << "{ \"$minKey\" : 1 }"; break; case MaxKey: s << "{ \"$maxKey\" : 1 }"; break; default: StringBuilder ss; ss << "Cannot create a properly formatted JSON string with " << "element: " << toString() << " of type: " << type(); string message = ss.str(); massert(10312, message.c_str(), false); } return s.str(); } int BSONElement::getGtLtOp(int def) const { const char* fn = fieldName(); if (fn[0] == '$' && fn[1]) { if (fn[2] == 't') { if (fn[1] == 'g') { if (fn[3] == 0) return BSONObj::GT; else if (fn[3] == 'e' && fn[4] == 0) return BSONObj::GTE; } else if (fn[1] == 'l') { if (fn[3] == 0) return BSONObj::LT; else if (fn[3] == 'e' && fn[4] == 0) return BSONObj::LTE; } } else if (fn[1] == 'n' && fn[2] == 'e') { if (fn[3] == 0) return BSONObj::NE; if (fn[3] == 'a' && fn[4] == 'r') // matches anything with $near prefix return BSONObj::opNEAR; } else if (fn[1] == 'm') { if (fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0) return BSONObj::opMOD; if (fn[2] == 'a' && fn[3] == 'x' && fn[4] == 'D' && fn[5] == 'i' && fn[6] == 's' && fn[7] == 't' && fn[8] == 'a' && fn[9] == 'n' && fn[10] == 'c' && fn[11] == 'e' && fn[12] == 0) return BSONObj::opMAX_DISTANCE; } else if (fn[1] == 't' && fn[2] == 'y' && fn[3] == 'p' && fn[4] == 'e' && fn[5] == 0) return BSONObj::opTYPE; else if (fn[1] == 'i' && fn[2] == 'n' && fn[3] == 0) { return BSONObj::opIN; } else if (fn[1] == 'n' && fn[2] == 'i' && fn[3] == 'n' && fn[4] == 0) return BSONObj::NIN; else if (fn[1] == 'a' && fn[2] == 'l' && fn[3] == 'l' && fn[4] == 0) return BSONObj::opALL; else if (fn[1] == 's' && fn[2] == 'i' && fn[3] == 'z' && fn[4] == 'e' && fn[5] == 0) return BSONObj::opSIZE; else if (fn[1] == 'e') { if (fn[2] == 'x' && fn[3] == 'i' && fn[4] == 's' && fn[5] == 't' && fn[6] == 's' && fn[7] == 0) return BSONObj::opEXISTS; if (fn[2] == 'l' && fn[3] == 'e' && fn[4] == 'm' && fn[5] == 'M' && fn[6] == 'a' && fn[7] == 't' && fn[8] == 'c' && fn[9] == 'h' && fn[10] == 0) return BSONObj::opELEM_MATCH; } else if (fn[1] == 'r' && fn[2] == 'e' && fn[3] == 'g' && fn[4] == 'e' && fn[5] == 'x' && fn[6] == 0) return BSONObj::opREGEX; else if (fn[1] == 'o' && fn[2] == 'p' && fn[3] == 't' && fn[4] == 'i' && fn[5] == 'o' && fn[6] == 'n' && fn[7] == 's' && fn[8] == 0) return BSONObj::opOPTIONS; else if (fn[1] == 'w' && fn[2] == 'i' && fn[3] == 't' && fn[4] == 'h' && fn[5] == 'i' && fn[6] == 'n' && fn[7] == 0) return BSONObj::opWITHIN; else if (str::equals(fn + 1, "geoIntersects")) return BSONObj::opGEO_INTERSECTS; else if (str::equals(fn + 1, "geoNear")) return BSONObj::opNEAR; else if (str::equals(fn + 1, "geoWithin")) return BSONObj::opWITHIN; } return def; } /** transform a BSON array into a vector of BSONElements. we match array # positions with their vector position, and ignore any fields with non-numeric field names. */ std::vector BSONElement::Array() const { chk(mongo::Array); std::vector v; BSONObjIterator i(Obj()); while (i.more()) { BSONElement e = i.next(); const char* f = e.fieldName(); unsigned u; Status status = parseNumberFromString(f, &u); if (status.isOK()) { verify(u < 1000000); if (u >= v.size()) v.resize(u + 1); v[u] = e; } else { // ignore? } } return v; } /* wo = "well ordered" note: (mongodb related) : this can only change in behavior when index version # changes */ int BSONElement::woCompare(const BSONElement& e, bool considerFieldName) const { int lt = (int)canonicalType(); int rt = (int)e.canonicalType(); int x = lt - rt; if (x != 0 && (!isNumber() || !e.isNumber())) return x; if (considerFieldName) { x = strcmp(fieldName(), e.fieldName()); if (x != 0) return x; } x = compareElementValues(*this, e); return x; } BSONObj BSONElement::embeddedObjectUserCheck() const { if (MONGO_likely(isABSONObj())) return BSONObj(value()); std::stringstream ss; ss << "invalid parameter: expected an object (" << fieldName() << ")"; uasserted(10065, ss.str()); return BSONObj(); // never reachable } BSONObj BSONElement::embeddedObject() const { verify(isABSONObj()); return BSONObj(value()); } BSONObj BSONElement::codeWScopeObject() const { verify(type() == CodeWScope); int strSizeWNull = ConstDataView(value() + 4).readLE(); return BSONObj(value() + 4 + 4 + strSizeWNull); } // wrap this element up as a singleton object. BSONObj BSONElement::wrap() const { BSONObjBuilder b(size() + 6); b.append(*this); return b.obj(); } BSONObj BSONElement::wrap(const StringData& newName) const { BSONObjBuilder b(size() + 6 + newName.size()); b.appendAs(*this, newName); return b.obj(); } void BSONElement::Val(BSONObj& v) const { v = Obj(); } BSONObj BSONElement::Obj() const { return embeddedObjectUserCheck(); } BSONElement BSONElement::operator[](const std::string& field) const { BSONObj o = Obj(); return o[field]; } int BSONElement::size(int maxLen) const { if (totalSize >= 0) return totalSize; int remain = maxLen - fieldNameSize() - 1; int x = 0; switch (type()) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: break; case mongo::Bool: x = 1; break; case NumberInt: x = 4; break; case mongo::Timestamp: case mongo::Date: case NumberDouble: case NumberLong: x = 8; break; case jstOID: x = OID::kOIDSize; break; case Symbol: case Code: case mongo::String: massert( 10313, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = valuestrsize() + 4; break; case CodeWScope: massert( 10314, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = objsize(); break; case DBRef: massert( 10315, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = valuestrsize() + 4 + 12; break; case Object: case mongo::Array: massert( 10316, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = objsize(); break; case BinData: massert( 10317, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = valuestrsize() + 4 + 1 /*subtype*/; break; case RegEx: { const char* p = value(); size_t len1 = (maxLen == -1) ? strlen(p) : strnlen(p, remain); massert(10318, "Invalid regex string", maxLen == -1 || len1 < size_t(remain)); p = p + len1 + 1; size_t len2; if (maxLen == -1) len2 = strlen(p); else { size_t x = remain - len1 - 1; verify(x <= 0x7fffffff); len2 = strnlen(p, x); massert(10319, "Invalid regex options string", len2 < x); } x = (int)(len1 + 1 + len2 + 1); } break; default: { massert(0, "This version of the MongoDB C++ driver does not support the Decimal128 BSON " "type. Please look for a newer version of the driver that supports it.", type() != 19); StringBuilder ss; ss << "BSONElement: bad type " << (int)type(); std::string msg = ss.str(); massert(13655, msg.c_str(), false); } } totalSize = x + fieldNameSize() + 1; // BSONType return totalSize; } int BSONElement::size() const { if (totalSize >= 0) return totalSize; int x = 0; switch (type()) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: break; case mongo::Bool: x = 1; break; case NumberInt: x = 4; break; case mongo::Timestamp: case mongo::Date: case NumberDouble: case NumberLong: x = 8; break; case jstOID: x = OID::kOIDSize; break; case Symbol: case Code: case mongo::String: x = valuestrsize() + 4; break; case DBRef: x = valuestrsize() + 4 + 12; break; case CodeWScope: case Object: case mongo::Array: x = objsize(); break; case BinData: x = valuestrsize() + 4 + 1 /*subtype*/; break; case RegEx: { const char* p = value(); size_t len1 = strlen(p); p = p + len1 + 1; size_t len2; len2 = strlen(p); x = (int)(len1 + 1 + len2 + 1); } break; default: { massert(0, "This version of the MongoDB C++ driver does not support the Decimal128 BSON " "type. Please look for a newer version of the driver that supports it.", type() != 19); StringBuilder ss; ss << "BSONElement: bad type " << (int)type(); std::string msg = ss.str(); massert(10320, msg.c_str(), false); } } totalSize = x + fieldNameSize() + 1; // BSONType return totalSize; } std::string BSONElement::toString(bool includeFieldName, bool full) const { StringBuilder s; toString(s, includeFieldName, full); return s.str(); } void BSONElement::toString(StringBuilder& s, bool includeFieldName, bool full, int depth) const { if (depth > BSONObj::maxToStringRecursionDepth) { // check if we want the full/complete string if (full) { StringBuilder s; s << "Reached maximum recursion depth of "; s << BSONObj::maxToStringRecursionDepth; uassert(16150, s.str(), full != true); } s << "..."; return; } if (includeFieldName && type() != EOO) s << fieldName() << ": "; switch (type()) { case EOO: s << "EOO"; break; case mongo::Date: s << "new Date(" << (long long)date() << ')'; break; case RegEx: { s << "/" << regex() << '/'; const char* p = regexFlags(); if (p) s << p; } break; case NumberDouble: s.appendDoubleNice(number()); break; case NumberLong: s << _numberLong(); break; case NumberInt: s << _numberInt(); break; case mongo::Bool: s << (boolean() ? "true" : "false"); break; case Object: embeddedObject().toString(s, false, full, depth + 1); break; case mongo::Array: embeddedObject().toString(s, true, full, depth + 1); break; case Undefined: s << "undefined"; break; case jstNULL: s << "null"; break; case MaxKey: s << "MaxKey"; break; case MinKey: s << "MinKey"; break; case CodeWScope: s << "CodeWScope( " << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")"; break; case Code: if (!full && valuestrsize() > 80) { s.write(valuestr(), 70); s << "..."; } else { s.write(valuestr(), valuestrsize() - 1); } break; case Symbol: case mongo::String: s << '"'; if (!full && valuestrsize() > 160) { s.write(valuestr(), 150); s << "...\""; } else { s.write(valuestr(), valuestrsize() - 1); s << '"'; } break; case DBRef: s << "DBRef('" << valuestr() << "',"; s << mongo::OID::from(valuestr() + valuestrsize()) << ')'; break; case jstOID: s << "ObjectId('"; s << __oid() << "')"; break; case BinData: s << "BinData(" << binDataType() << ", "; { int len; const char* data = binDataClean(len); if (!full && len > 80) { s << toHex(data, 70) << "...)"; } else { s << toHex(data, len) << ")"; } } break; case mongo::Timestamp: { Timestamp_t ts = timestamp(); s << "Timestamp " << ts.seconds() << "|" << ts.increment(); break; } default: s << "?type=" << type(); break; } } std::string BSONElement::_asCode() const { switch (type()) { case mongo::String: case Code: return std::string(valuestr(), valuestrsize() - 1); case CodeWScope: return std::string(codeWScopeCode(), ConstDataView(valuestr()).readLE() - 1); default: log() << "can't convert type: " << (int)(type()) << " to code" << std::endl; } uassert(10062, "not code", 0); return ""; } std::ostream& operator<<(std::ostream& s, const BSONElement& e) { return s << e.toString(); } StringBuilder& operator<<(StringBuilder& s, const BSONElement& e) { e.toString(s); return s; } template <> bool BSONElement::coerce(std::string* out) const { if (type() != mongo::String) return false; *out = String(); return true; } template <> bool BSONElement::coerce(int* out) const { if (!isNumber()) return false; *out = numberInt(); return true; } template <> bool BSONElement::coerce(long long* out) const { if (!isNumber()) return false; *out = numberLong(); return true; } template <> bool BSONElement::coerce(double* out) const { if (!isNumber()) return false; *out = numberDouble(); return true; } template <> bool BSONElement::coerce(bool* out) const { *out = trueValue(); return true; } template <> bool BSONElement::coerce >(std::vector* out) const { if (type() != mongo::Array) return false; return Obj().coerceVector(out); } template bool BSONObj::coerceVector(std::vector* out) const { BSONObjIterator i(*this); while (i.more()) { BSONElement e = i.next(); T t; if (!e.coerce(&t)) return false; out->push_back(t); } return true; } // used by jsonString() std::string escape(const std::string& s, bool escape_slash) { StringBuilder ret; for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { switch (*i) { case '"': ret << "\\\""; break; case '\\': ret << "\\\\"; break; case '/': ret << (escape_slash ? "\\/" : "/"); break; case '\b': ret << "\\b"; break; case '\f': ret << "\\f"; break; case '\n': ret << "\\n"; break; case '\r': ret << "\\r"; break; case '\t': ret << "\\t"; break; default: if (*i >= 0 && *i <= 0x1f) { // TODO: these should be utf16 code-units not bytes char c = *i; ret << "\\u00" << toHexLower(&c, 1); } else { ret << *i; } } } return ret.str(); } /** * l and r must be same canonicalType when called. */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; switch (l.type()) { case EOO: case Undefined: // EOO and Undefined are same canonicalType case jstNULL: case MaxKey: case MinKey: f = l.canonicalType() - r.canonicalType(); if (f < 0) return -1; return f == 0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: // unsigned compare for timestamps - note they are not really dates // but (ordinal + time_t) if (l.date() < r.date()) return -1; return l.date() == r.date() ? 0 : 1; case Date: // Signed comparisons for Dates. { long long a = (long long)l.Date().millis; long long b = (long long)r.Date().millis; if (a < b) return -1; return a == b ? 0 : 1; } case NumberInt: { // All types can precisely represent all NumberInts, so it is safe to simply convert to // whatever rhs's type is. switch (r.type()) { case NumberInt: return compareInts(l._numberInt(), r._numberInt()); case NumberLong: return compareLongs(l._numberInt(), r._numberLong()); case NumberDouble: return compareDoubles(l._numberInt(), r._numberDouble()); default: invariant(false); } } case NumberLong: { switch (r.type()) { case NumberLong: return compareLongs(l._numberLong(), r._numberLong()); case NumberInt: return compareLongs(l._numberLong(), r._numberInt()); case NumberDouble: return compareLongToDouble(l._numberLong(), r._numberDouble()); default: invariant(false); } } case NumberDouble: { switch (r.type()) { case NumberDouble: return compareDoubles(l._numberDouble(), r._numberDouble()); case NumberInt: return compareDoubles(l._numberDouble(), r._numberInt()); case NumberLong: return compareDoubleToLong(l._numberDouble(), r._numberLong()); default: invariant(false); } } case jstOID: return memcmp(l.value(), r.value(), OID::kOIDSize); case Code: case Symbol: case String: /* todo: a utf sort order version one day... */ { // we use memcmp as we allow zeros in UTF8 strings int lsz = l.valuestrsize(); int rsz = r.valuestrsize(); int common = std::min(lsz, rsz); int res = memcmp(l.valuestr(), r.valuestr(), common); if (res) return res; // longer string is the greater one return lsz - rsz; } case Object: case Array: return l.embeddedObject().woCompare(r.embeddedObject()); case DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BinData: { int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value() + 4, r.value() + 4, lsz + 1 /*+1 for subtype byte*/); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if (c) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case CodeWScope: { int cmp = StringData(l.codeWScopeCode(), l.codeWScopeCodeLen() - 1) .compare(StringData(r.codeWScopeCode(), r.codeWScopeCodeLen() - 1)); if (cmp) return cmp; return l.codeWScopeObject().woCompare(r.codeWScopeObject()); } default: verify(false); } return -1; } size_t BSONElement::Hasher::operator()(const BSONElement& elem) const { size_t hash = 0; boost::hash_combine(hash, elem.canonicalType()); const StringData fieldName = elem.fieldNameStringData(); if (!fieldName.empty()) { boost::hash_combine(hash, StringData::Hasher()(fieldName)); } switch (elem.type()) { // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: case mongo::jstNULL: case mongo::MaxKey: case mongo::MinKey: // These are valueless types break; case mongo::Bool: boost::hash_combine(hash, elem.boolean()); break; case mongo::Timestamp: // TODO: Verify this boost::hash_combine(hash, elem._numberLong()); break; case mongo::Date: boost::hash_combine(hash, elem.date().asInt64()); break; case mongo::NumberDouble: case mongo::NumberLong: case mongo::NumberInt: { // This converts all numbers to doubles, which ignores the low-order bits of // NumberLongs > 2**53, but that is ok since the hash will still be the same for // equal numbers and is still likely to be different for different numbers. // SERVER-16851 const double dbl = elem.numberDouble(); if (isNaN(dbl)) { boost::hash_combine(hash, std::numeric_limits::quiet_NaN()); } else { boost::hash_combine(hash, dbl); } break; } case mongo::jstOID: elem.__oid().hash_combine(hash); break; case mongo::Code: case mongo::Symbol: case mongo::String: boost::hash_combine(hash, StringData::Hasher()(elem.valueStringData())); break; case mongo::Object: case mongo::Array: boost::hash_combine(hash, BSONObj::Hasher()(elem.embeddedObject())); break; case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. boost::hash_combine(hash, StringData::Hasher()(StringData(elem.value(), elem.valuesize()))); break; case mongo::RegEx: boost::hash_combine(hash, StringData::Hasher()(elem.regex())); boost::hash_combine(hash, StringData::Hasher()(elem.regexFlags())); break; case mongo::CodeWScope: { boost::hash_combine( hash, StringData::Hasher()(StringData(elem.codeWScopeCode(), elem.codeWScopeCodeLen()))); boost::hash_combine(hash, BSONObj::Hasher()(elem.codeWScopeObject())); break; } } return hash; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonelement.h000066400000000000000000000530301273231111400235140ustar00rootroot00000000000000// bsonelement.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include // strlen #include #include #include "mongo/base/data_cursor.h" #include "mongo/bson/bsontypes.h" #include "mongo/bson/oid.h" #include "mongo/bson/timestamp.h" #include "mongo/client/export_macros.h" #include "mongo/platform/cstdint.h" #include "mongo/platform/float_utils.h" #include "mongo/platform/strnlen.h" namespace mongo { class BSONObj; class BSONElement; class BSONObjBuilder; /* l and r MUST have same type when called: check that first. */ int compareElementValues(const BSONElement& l, const BSONElement& r); /** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" }, 'a : 3' is the first element (key+value). The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope for the life of the BSONElement. internals: -------- size() ------------ -fieldNameSize- value() type() */ class MONGO_CLIENT_API BSONElement { public: /** These functions, which start with a capital letter, throw a MsgAssertionException if the element is not of the required type. Example: std::string foo = obj["foo"].String(); // std::exception if not a std::string type or DNE */ std::string String() const { return chk(mongo::String).str(); } const StringData checkAndGetStringData() const { return chk(mongo::String).valueStringData(); } Date_t Date() const { return chk(mongo::Date).date(); } double Number() const { return chk(isNumber()).number(); } double Double() const { return chk(NumberDouble)._numberDouble(); } long long Long() const { return chk(NumberLong)._numberLong(); } int Int() const { return chk(NumberInt)._numberInt(); } bool Bool() const { return chk(mongo::Bool).boolean(); } std::vector Array() const; // see implementation for detailed comments mongo::OID OID() const { return chk(jstOID).__oid(); } void Null() const { chk(isNull()); } // throw MsgAssertionException if not null void OK() const { chk(ok()); } // throw MsgAssertionException if element DNE Timestamp_t Timestamp() const { return chk(mongo::Timestamp).timestamp(); } /** @return the embedded object associated with this field. Note the returned object is a reference to within the parent bson object. If that object is out of scope, this pointer will no longer be valid. Call getOwned() on the returned BSONObj if you need your own copy. throws UserException if the element is not of type object. */ BSONObj Obj() const; /** populate v with the value of the element. If type does not match, throw exception. useful in templates -- see also BSONObj::Vals(). */ void Val(Date_t& v) const { v = Date(); } void Val(long long& v) const { v = Long(); } void Val(bool& v) const { v = Bool(); } void Val(BSONObj& v) const; void Val(mongo::OID& v) const { v = OID(); } void Val(int& v) const { v = Int(); } void Val(double& v) const { v = Double(); } void Val(std::string& v) const { v = String(); } /** Use ok() to check if a value is assigned: if( myObj["foo"].ok() ) ... */ bool ok() const { return !eoo(); } std::string toString(bool includeFieldName = true, bool full = false) const; void toString(StringBuilder& s, bool includeFieldName = true, bool full = false, int depth = 0) const; std::string jsonString(JsonStringFormat format, bool includeFieldNames = true, int pretty = 0) const; operator std::string() const { return toString(); } /** Returns the type of the element */ BSONType type() const { const signed char typeByte = ConstDataView(data).readLE(); return static_cast(typeByte); } /** retrieve a field within this element throws exception if *this is not an embedded object */ BSONElement operator[](const std::string& field) const; /** See canonicalizeBSONType in bsontypes.h */ int canonicalType() const { return canonicalizeBSONType(type()); } /** Indicates if it is the end-of-object element, which is present at the end of every BSON object. */ bool eoo() const { return type() == EOO; } /** Size of the element. @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size. */ int size(int maxLen) const; int size() const; /** Wrap this element up as a singleton object. */ BSONObj wrap() const; /** Wrap this element up as a singleton object with a new name. */ BSONObj wrap(const StringData& newName) const; /** field name of the element. e.g., for name : "Joe" "name" is the fieldname */ const char* fieldName() const { if (eoo()) return ""; // no fieldname for it. return data + 1; } /** * NOTE: size includes the NULL terminator. */ int fieldNameSize() const { if (fieldNameSize_ == -1) fieldNameSize_ = (int)strlen(fieldName()) + 1; return fieldNameSize_; } const StringData fieldNameStringData() const { return StringData(fieldName(), eoo() ? 0 : fieldNameSize() - 1); } /** raw data of the element's value (so be careful). */ const char* value() const { return (data + fieldNameSize() + 1); } /** size in bytes of the element's value (when applicable). */ int valuesize() const { return size() - fieldNameSize() - 1; } bool isBoolean() const { return type() == mongo::Bool; } /** @return value of a boolean element. You must assure element is a boolean before calling. */ bool boolean() const { return *value() ? true : false; } bool booleanSafe() const { return isBoolean() && boolean(); } /** Retrieve a java style date value from the element. Ensure element is of type Date before calling. @see Bool(), trueValue() */ Date_t date() const { return Date_t(ConstDataView(value()).readLE()); } /** Convert the value to boolean, regardless of its type, in a javascript-like fashion (i.e., treats zero and null and eoo as false). */ bool trueValue() const; /** True if number, string, bool, date, OID */ bool isSimpleType() const; /** True if element is of a numeric type. */ bool isNumber() const; /** Return double value for this field. MUST be NumberDouble type. */ double _numberDouble() const { return ConstDataView(value()).readLE(); } /** Return int value for this field. MUST be NumberInt type. */ int _numberInt() const { return ConstDataView(value()).readLE(); } /** Return long long value for this field. MUST be NumberLong type. */ long long _numberLong() const { return ConstDataView(value()).readLE(); } /** Retrieve int value for the element safely. Zero returned if not a number. */ int numberInt() const; /** Retrieve long value for the element safely. Zero returned if not a number. * Behavior is not defined for double values that are NaNs, or too large/small * to be represented by long longs */ long long numberLong() const; /** Like numberLong() but with well-defined behavior for doubles that * are NaNs, or too large/small to be represented as long longs. * NaNs -> 0 * very large doubles -> LLONG_MAX * very small doubles -> LLONG_MIN */ long long safeNumberLong() const; /** Retrieve the numeric value of the element. If not of a numeric type, returns 0. Note: casts to double, data loss may occur with large (>52 bit) NumberLong values. */ double numberDouble() const; /** Retrieve the numeric value of the element. If not of a numeric type, returns 0. Note: casts to double, data loss may occur with large (>52 bit) NumberLong values. */ double number() const { return numberDouble(); } /** Retrieve the object ID stored in the object. You must ensure the element is of type jstOID first. */ mongo::OID __oid() const { return OID::from(value()); } /** True if element is null. */ bool isNull() const { return type() == jstNULL; } /** Size (length) of a string element. You must assure of type String first. @return string size including terminating null */ int valuestrsize() const { return ConstDataView(value()).readLE(); } // for objects the size *includes* the size of the size field size_t objsize() const { return ConstDataView(value()).readLE(); } /** Get a string's value. Also gives you start of the real data for an embedded object. You must assure data is of an appropriate type first -- see also valuestrsafe(). */ const char* valuestr() const { return value() + 4; } /** Get the string value of the element. If not a string returns "". */ const char* valuestrsafe() const { return type() == mongo::String ? valuestr() : ""; } /** Get the string value of the element. If not a string returns "". */ std::string str() const { return type() == mongo::String ? std::string(valuestr(), valuestrsize() - 1) : std::string(); } /** * Returns a StringData pointing into this element's data. Does not validate that the * element is actually of type String. */ const StringData valueStringData() const { return StringData(valuestr(), valuestrsize() - 1); } /** Get javascript code of a CodeWScope data element. */ const char* codeWScopeCode() const { massert(16177, "not codeWScope", type() == CodeWScope); return value() + 4 + 4; // two ints precede code (see BSON spec) } /** Get length of the code part of the CodeWScope object * This INCLUDES the null char at the end */ int codeWScopeCodeLen() const { massert(16178, "not codeWScope", type() == CodeWScope); return ConstDataView(value() + 4).readLE(); } /** Get the scope SavedContext of a CodeWScope data element. * * This function is DEPRECATED, since it can error if there are * null chars in the codeWScopeCode. However, some existing indexes * may be based on an incorrect ordering derived from this function, * so it may still need to be used in certain cases. * */ const char* codeWScopeScopeDataUnsafe() const { // This can error if there are null chars in the codeWScopeCode return codeWScopeCode() + strlen(codeWScopeCode()) + 1; } /* Get the scope SavedContext of a CodeWScope data element. * * This is the corrected version of codeWScopeScopeDataUnsafe(), * but note that existing uses might rely on the behavior of * that function so be careful in choosing which version to use. */ const char* codeWScopeScopeData() const { return codeWScopeCode() + codeWScopeCodeLen(); } /** Get the embedded object this element holds. */ BSONObj embeddedObject() const; /* uasserts if not an object */ BSONObj embeddedObjectUserCheck() const; BSONObj codeWScopeObject() const; /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */ const char* binData(int& len) const { // BinData: verify(type() == BinData); len = valuestrsize(); return value() + 5; } /** Get binary data. Element must be of type BinData. Handles type 2 */ const char* binDataClean(int& len) const { // BinData: if (binDataType() != ByteArrayDeprecated) { return binData(len); } else { // Skip extra size len = valuestrsize() - 4; return value() + 5 + 4; } } BinDataType binDataType() const { // BinData: verify(type() == BinData); unsigned char c = (value() + 4)[0]; return (BinDataType)c; } /** Retrieve the regex string for a Regex element */ const char* regex() const { verify(type() == RegEx); return value(); } /** Retrieve the regex flags (options) for a Regex element */ const char* regexFlags() const { const char* p = regex(); return p + strlen(p) + 1; } /** like operator== but doesn't check the fieldname, just the value. */ bool valuesEqual(const BSONElement& r) const { return woCompare(r, false) == 0; } /** Returns true if elements are equal. */ bool operator==(const BSONElement& r) const { return woCompare(r, true) == 0; } /** Returns true if elements are unequal. */ bool operator!=(const BSONElement& r) const { return !operator==(r); } /** Well ordered comparison. @return <0: l0:l>r order by type, field name, and field value. If considerFieldName is true, pay attention to the field name. */ int woCompare(const BSONElement& e, bool considerFieldName = true) const; /** * Functor compatible with std::hash for std::unordered_{map,set} * Warning: The hash function is subject to change. Do not use in cases where hashes need * to be consistent across versions. */ struct Hasher { size_t operator()(const BSONElement& elem) const; }; const char* rawdata() const { return data; } /** 0 == Equality, just not defined yet */ int getGtLtOp(int def = 0) const; /** Constructs an empty element */ BSONElement(); /** True if this element may contain subobjects. */ bool mayEncapsulate() const { switch (type()) { case Object: case mongo::Array: case CodeWScope: return true; default: return false; } } /** True if this element can be a BSONObj */ bool isABSONObj() const { switch (type()) { case Object: case mongo::Array: return true; default: return false; } } Timestamp_t timestamp() const { ConstDataCursor cursor(value()); const uint32_t increment = cursor.readLEAndAdvance(); const uint32_t seconds = cursor.readLE(); return Timestamp_t(seconds, increment); } const char* dbrefNS() const { uassert(10063, "not a dbref", type() == DBRef); return value() + 4; } const mongo::OID dbrefOID() const { uassert(10064, "not a dbref", type() == DBRef); const char* start = value(); start += 4 + ConstDataView(start).readLE(); return mongo::OID::from(start); } /** this does not use fieldName in the comparison, just the value */ bool operator<(const BSONElement& other) const { int x = (int)canonicalType() - (int)other.canonicalType(); if (x < 0) return true; else if (x > 0) return false; return compareElementValues(*this, other) < 0; } // @param maxLen don't scan more than maxLen bytes explicit BSONElement(const char* d, int maxLen) : data(d) { if (eoo()) { totalSize = 1; fieldNameSize_ = 0; } else { totalSize = -1; fieldNameSize_ = -1; if (maxLen != -1) { size_t size = strnlen(fieldName(), maxLen - 1); uassert(10333, "Invalid field name", size < size_t(maxLen - 1)); fieldNameSize_ = size + 1; } } } explicit BSONElement(const char* d) : data(d) { fieldNameSize_ = -1; totalSize = -1; if (eoo()) { fieldNameSize_ = 0; totalSize = 1; } } struct FieldNameSizeTag {}; // For disambiguation with ctor taking 'maxLen' above. /** Construct a BSONElement where you already know the length of the name. The value * passed here includes the null terminator. The data pointed to by 'd' must not * represent an EOO. You may pass -1 to indicate that you don't actually know the * size. */ BSONElement(const char* d, int fieldNameSize, FieldNameSizeTag) : data(d), fieldNameSize_(fieldNameSize) // internal size includes null terminator , totalSize(-1) {} std::string _asCode() const; template bool coerce(T* out) const; private: const char* data; mutable int fieldNameSize_; // cached value mutable int totalSize; /* caches the computed size */ friend class BSONObjIterator; friend class BSONObj; const BSONElement& chk(int t) const { if (t != type()) { StringBuilder ss; if (eoo()) ss << "field not found, expected type " << t; else ss << "wrong type for field (" << fieldName() << ") " << type() << " != " << t; msgasserted(13111, ss.str()); } return *this; } const BSONElement& chk(bool expr) const { massert(13118, "unexpected or missing type value in BSON object", expr); return *this; } }; inline bool BSONElement::trueValue() const { // NOTE Behavior changes must be replicated in Value::coerceToBool(). switch (type()) { case NumberLong: return _numberLong() != 0; case NumberDouble: return _numberDouble() != 0; case NumberInt: return _numberInt() != 0; case mongo::Bool: return boolean(); case EOO: case jstNULL: case Undefined: return false; default: ; } return true; } /** @return true if element is of a numeric type. */ inline bool BSONElement::isNumber() const { switch (type()) { case NumberLong: case NumberDouble: case NumberInt: return true; default: return false; } } inline bool BSONElement::isSimpleType() const { switch (type()) { case NumberLong: case NumberDouble: case NumberInt: case mongo::String: case mongo::Bool: case mongo::Date: case jstOID: return true; default: return false; } } inline double BSONElement::numberDouble() const { switch (type()) { case NumberDouble: return _numberDouble(); case NumberInt: return _numberInt(); case NumberLong: return _numberLong(); default: return 0; } } /** Retrieve int value for the element safely. Zero returned if not a number. * Converted to int if another numeric type. */ inline int BSONElement::numberInt() const { switch (type()) { case NumberDouble: return (int)_numberDouble(); case NumberInt: return _numberInt(); case NumberLong: return (int)_numberLong(); default: return 0; } } /** Retrieve long value for the element safely. Zero returned if not a number. */ inline long long BSONElement::numberLong() const { switch (type()) { case NumberDouble: return (long long)_numberDouble(); case NumberInt: return _numberInt(); case NumberLong: return _numberLong(); default: return 0; } } /** Like numberLong() but with well-defined behavior for doubles that * are NaNs, or too large/small to be represented as long longs. * NaNs -> 0 * very large doubles -> LLONG_MAX * very small doubles -> LLONG_MIN */ inline long long BSONElement::safeNumberLong() const { double d; switch (type()) { case NumberDouble: d = numberDouble(); if (isNaN(d)) { return 0; } if (d > (double)std::numeric_limits::max()) { return std::numeric_limits::max(); } if (d < std::numeric_limits::min()) { return std::numeric_limits::min(); } default: return numberLong(); } } inline BSONElement::BSONElement() { static const char kEooElement[] = ""; data = kEooElement; fieldNameSize_ = 0; totalSize = 1; } // TODO(SERVER-14596): move to a better place; take a StringData. std::string escape(const std::string& s, bool escape_slash = false); } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonmisc.cpp000066400000000000000000000053701273231111400233550ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/db/jsobj.h" namespace mongo { int getGtLtOp(const BSONElement& e) { if (e.type() != Object) return BSONObj::Equality; BSONElement fe = e.embeddedObject().firstElement(); return fe.getGtLtOp(); } bool fieldsMatch(const BSONObj& lhs, const BSONObj& rhs) { BSONObjIterator l(lhs); BSONObjIterator r(rhs); while (l.more() && r.more()) { if (strcmp(l.next().fieldName(), r.next().fieldName())) { return false; } } return !(l.more() || r.more()); // false if lhs and rhs have diff nFields() } Labeler::Label GT("$gt"); Labeler::Label GTE("$gte"); Labeler::Label LT("$lt"); Labeler::Label LTE("$lte"); Labeler::Label NE("$ne"); Labeler::Label NIN("$nin"); Labeler::Label BSIZE("$size"); GENOIDLabeler GENOID; DateNowLabeler DATENOW; NullLabeler BSONNULL; UndefinedLabeler BSONUndefined; MinKeyLabeler MINKEY; MaxKeyLabeler MAXKEY; BSONObjBuilderValueStream::BSONObjBuilderValueStream(BSONObjBuilder* builder) { _builder = builder; } BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const BSONElement& e) { _builder->appendAs(e, _fieldName); _fieldName = StringData(); return *_builder; } BufBuilder& BSONObjBuilderValueStream::subobjStart() { StringData tmp = _fieldName; _fieldName = StringData(); return _builder->subobjStart(tmp); } BufBuilder& BSONObjBuilderValueStream::subarrayStart() { StringData tmp = _fieldName; _fieldName = StringData(); return _builder->subarrayStart(tmp); } Labeler BSONObjBuilderValueStream::operator<<(const Labeler::Label& l) { return Labeler(l, this); } void BSONObjBuilderValueStream::endField(const StringData& nextFieldName) { if (haveSubobj()) { verify(_fieldName.rawData()); _builder->append(_fieldName, subobj()->done()); _subobj.reset(); } _fieldName = nextFieldName; } BSONObjBuilder* BSONObjBuilderValueStream::subobj() { if (!haveSubobj()) _subobj.reset(new BSONObjBuilder()); return _subobj.get(); } BSONObjBuilder& Labeler::operator<<(const BSONElement& e) { s_->subobj()->appendAs(e, l_.l_); return *s_->_builder; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonmisc.h000066400000000000000000000207541273231111400230250ustar00rootroot00000000000000// @file bsonmisc.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/bson/bsonelement.h" #include "mongo/client/export_macros.h" namespace mongo { int getGtLtOp(const BSONElement& e); struct BSONElementCmpWithoutField { bool operator()(const BSONElement& l, const BSONElement& r) const { return l.woCompare(r, false) < 0; } }; class BSONObjCmp { public: BSONObjCmp(const BSONObj& order = BSONObj()) : _order(order) {} bool operator()(const BSONObj& l, const BSONObj& r) const { return l.woCompare(r, _order) < 0; } BSONObj order() const { return _order; } private: BSONObj _order; }; typedef std::set BSONObjSet; enum FieldCompareResult { LEFT_SUBFIELD = -2, LEFT_BEFORE = -1, SAME = 0, RIGHT_BEFORE = 1, RIGHT_SUBFIELD = 2 }; /** Use BSON macro to build a BSONObj from a stream e.g., BSON( "name" << "joe" << "age" << 33 ) with auto-generated object id: BSON( GENOID << "name" << "joe" << "age" << 33 ) The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction of a BSONObj, particularly when assembling a Query. For example, BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }. */ #define BSON(x) ((::mongo::BSONObjBuilder(64) << x).obj()) /** Use BSON_ARRAY macro like BSON macro, but without keys BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) ); */ #define BSON_ARRAY(x) ((::mongo::BSONArrayBuilder() << x).arr()) /* Utility class to auto assign object IDs. Example: std::cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } */ struct MONGO_CLIENT_API GENOIDLabeler {}; extern MONGO_CLIENT_API GENOIDLabeler GENOID; /* Utility class to add a Date element with the current time Example: std::cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 11:41:42" } */ struct MONGO_CLIENT_API DateNowLabeler {}; extern MONGO_CLIENT_API DateNowLabeler DATENOW; /* Utility class to assign a NULL value to a given attribute Example: std::cout << BSON( "a" << BSONNULL ); // { a : null } */ struct MONGO_CLIENT_API NullLabeler {}; extern MONGO_CLIENT_API NullLabeler BSONNULL; /* Utility class to assign an Undefined value to a given attribute Example: std::cout << BSON( "a" << BSONUndefined ); // { a : undefined } */ struct MONGO_CLIENT_API UndefinedLabeler {}; extern MONGO_CLIENT_API UndefinedLabeler BSONUndefined; /* Utility class to add the minKey (minus infinity) to a given attribute Example: std::cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } } */ struct MONGO_CLIENT_API MinKeyLabeler {}; extern MONGO_CLIENT_API MinKeyLabeler MINKEY; struct MONGO_CLIENT_API MaxKeyLabeler {}; extern MONGO_CLIENT_API MaxKeyLabeler MAXKEY; // Utility class to implement GT, GTE, etc as described above. class Labeler { public: struct Label { explicit Label(const char* l) : l_(l) {} const char* l_; }; Labeler(const Label& l, BSONObjBuilderValueStream* s) : l_(l), s_(s) {} template BSONObjBuilder& operator<<(T value); /* the value of the element e is appended i.e. for "age" << GT << someElement one gets { age : { $gt : someElement's value } } */ BSONObjBuilder& operator<<(const BSONElement& e); private: const Label& l_; BSONObjBuilderValueStream* s_; }; // Utility class to allow adding a string to BSON as a Symbol struct BSONSymbol { explicit BSONSymbol(const StringData& sym) : symbol(sym) {} StringData symbol; }; // Utility class to allow adding a string to BSON as Code struct BSONCode { explicit BSONCode(const StringData& str) : code(str) {} StringData code; }; // Utility class to allow adding CodeWScope to BSON struct BSONCodeWScope { explicit BSONCodeWScope(const StringData& str, const BSONObj& obj) : code(str), scope(obj) {} StringData code; BSONObj scope; }; // Utility class to allow adding a RegEx to BSON struct BSONRegEx { explicit BSONRegEx(const StringData& pat, const StringData& f = "") : pattern(pat), flags(f) {} StringData pattern; StringData flags; }; // Utility class to allow adding binary data to BSON struct BSONBinData { BSONBinData(const void* d, int l, BinDataType t) : data(d), length(l), type(t) {} const void* data; int length; BinDataType type; }; // Utility class to allow adding deprecated DBRef type to BSON struct BSONDBRef { BSONDBRef(const StringData& nameSpace, const OID& o) : ns(nameSpace), oid(o) {} StringData ns; OID oid; }; extern MONGO_CLIENT_API Labeler::Label GT; extern MONGO_CLIENT_API Labeler::Label GTE; extern MONGO_CLIENT_API Labeler::Label LT; extern MONGO_CLIENT_API Labeler::Label LTE; extern MONGO_CLIENT_API Labeler::Label NE; extern MONGO_CLIENT_API Labeler::Label NIN; extern MONGO_CLIENT_API Labeler::Label BSIZE; // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6)); // becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]} inline BSONObj OR(const BSONObj& a, const BSONObj& b); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d); inline BSONObj OR( const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f); // definitions in bsonobjbuilder.h b/c of incomplete types // Utility class to implement BSON( key << val ) as described above. class MONGO_CLIENT_API BSONObjBuilderValueStream : public boost::noncopyable { public: friend class Labeler; BSONObjBuilderValueStream(BSONObjBuilder* builder); BSONObjBuilder& operator<<(const BSONElement& e); template BSONObjBuilder& operator<<(T value); BSONObjBuilder& operator<<(const DateNowLabeler& id); BSONObjBuilder& operator<<(const NullLabeler& id); BSONObjBuilder& operator<<(const UndefinedLabeler& id); BSONObjBuilder& operator<<(const MinKeyLabeler& id); BSONObjBuilder& operator<<(const MaxKeyLabeler& id); Labeler operator<<(const Labeler::Label& l); void endField(const StringData& nextFieldName = StringData()); bool subobjStarted() const { return _fieldName != 0; } // The following methods provide API compatibility with BSONArrayBuilder BufBuilder& subobjStart(); BufBuilder& subarrayStart(); // This method should only be called from inside of implementations of // BSONObjBuilder& operator<<(BSONObjBuilderValueStream&, SOME_TYPE) // to provide the return value. BSONObjBuilder& builder() { return *_builder; } private: StringData _fieldName; BSONObjBuilder* _builder; bool haveSubobj() const { return _subobj.get() != 0; } BSONObjBuilder* subobj(); std::auto_ptr _subobj; }; /** used in conjuction with BSONObjBuilder, allows for proper buffer size to prevent crazy memory usage */ class BSONSizeTracker { public: BSONSizeTracker() { _pos = 0; for (int i = 0; i < SIZE; i++) _sizes[i] = 512; // this is the default, so just be consistent } ~BSONSizeTracker() {} void got(int size) { _sizes[_pos] = size; _pos = (_pos + 1) % SIZE; // thread safe at least on certain compilers } /** * right now choosing largest size */ int getSize() const { int x = 16; // sane min for (int i = 0; i < SIZE; i++) { if (_sizes[i] > x) x = _sizes[i]; } return x; } private: enum { SIZE = 10 }; int _pos; int _sizes[SIZE]; }; // considers order bool fieldsMatch(const BSONObj& lhs, const BSONObj& rhs); } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobj.cpp000066400000000000000000000555711273231111400232040ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/db/jsobj.h" #include #include "mongo/bson/bson_validate.h" #include "mongo/db/json.h" #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" namespace mongo { using namespace std; /* BSONObj ------------------------------------------------------------*/ // deep (full) equality bool BSONObj::equal(const BSONObj& rhs) const { BSONObjIterator i(*this); BSONObjIterator j(rhs); BSONElement l, r; do { // so far, equal... l = i.next(); r = j.next(); if (l.eoo()) return r.eoo(); } while (l == r); return false; } void BSONObj::_assertInvalid() const { StringBuilder ss; int os = objsize(); ss << "BSONObj size: " << os << " (0x" << integerToHex(os) << ") is invalid. " << "Size must be between 0 and " << BSONObjMaxInternalSize << "(" << (BSONObjMaxInternalSize / (1024 * 1024)) << "MB)"; try { BSONElement e = firstElement(); ss << " First element: " << e.toString(); } catch (...) { } massert(10334, ss.str(), 0); } BSONObj BSONObj::copy() const { char* storage = static_cast(malloc(sizeof(Holder) + objsize())); memcpy(storage + sizeof(Holder), objdata(), objsize()); return BSONObj::takeOwnership(storage); } BSONObj BSONObj::getOwned() const { if (isOwned()) return *this; return copy(); } BSONObjIterator BSONObj::begin() const { return BSONObjIterator(*this); } string BSONObj::jsonString(JsonStringFormat format, int pretty, bool isArray) const { if (isEmpty()) return isArray ? "[]" : "{}"; StringBuilder s; s << (isArray ? "[ " : "{ "); BSONObjIterator i(*this); BSONElement e = i.next(); if (!e.eoo()) while (1) { s << e.jsonString(format, !isArray, pretty ? pretty + 1 : 0); e = i.next(); if (e.eoo()) break; s << ","; if (pretty) { s << '\n'; for (int x = 0; x < pretty; x++) s << " "; } else { s << " "; } } s << (isArray ? " ]" : " }"); return s.str(); } bool BSONObj::valid() const { return validateBSON(objdata(), objsize()).isOK(); } int BSONObj::woCompare(const BSONObj& r, const Ordering& o, bool considerFieldName) const { if (isEmpty()) return r.isEmpty() ? 0 : -1; if (r.isEmpty()) return 1; BSONObjIterator i(*this); BSONObjIterator j(r); unsigned mask = 1; while (1) { // so far, equal... BSONElement l = i.next(); BSONElement r = j.next(); if (l.eoo()) return r.eoo() ? 0 : -1; if (r.eoo()) return 1; int x; { x = l.woCompare(r, considerFieldName); if (o.descending(mask)) x = -x; } if (x != 0) return x; mask <<= 1; } return -1; } /* well ordered compare */ int BSONObj::woCompare(const BSONObj& r, const BSONObj& idxKey, bool considerFieldName) const { if (isEmpty()) return r.isEmpty() ? 0 : -1; if (r.isEmpty()) return 1; bool ordered = !idxKey.isEmpty(); BSONObjIterator i(*this); BSONObjIterator j(r); BSONObjIterator k(idxKey); while (1) { // so far, equal... BSONElement l = i.next(); BSONElement r = j.next(); BSONElement o; if (ordered) o = k.next(); if (l.eoo()) return r.eoo() ? 0 : -1; if (r.eoo()) return 1; int x; /* if( ordered && o.type() == String && strcmp(o.valuestr(), "ascii-proto") == 0 && l.type() == String && r.type() == String ) { // note: no negative support yet, as this is just sort of a POC x = _stricmp(l.valuestr(), r.valuestr()); } else*/ { x = l.woCompare(r, considerFieldName); if (ordered && o.number() < 0) x = -x; } if (x != 0) return x; } return -1; } BSONObj staticNull = fromjson("{'':null}"); BSONObj makeUndefined() { BSONObjBuilder b; b.appendUndefined(""); return b.obj(); } BSONObj staticUndefined = makeUndefined(); /* well ordered compare */ int BSONObj::woSortOrder(const BSONObj& other, const BSONObj& sortKey, bool useDotted) const { if (isEmpty()) return other.isEmpty() ? 0 : -1; if (other.isEmpty()) return 1; uassert(10060, "woSortOrder needs a non-empty sortKey", !sortKey.isEmpty()); BSONObjIterator i(sortKey); while (1) { BSONElement f = i.next(); if (f.eoo()) return 0; BSONElement l = useDotted ? getFieldDotted(f.fieldName()) : getField(f.fieldName()); if (l.eoo()) l = staticNull.firstElement(); BSONElement r = useDotted ? other.getFieldDotted(f.fieldName()) : other.getField(f.fieldName()); if (r.eoo()) r = staticNull.firstElement(); int x = l.woCompare(r, false); if (f.number() < 0) x = -x; if (x != 0) return x; } return -1; } size_t BSONObj::Hasher::operator()(const BSONObj& obj) const { size_t hash = 0; BSONForEach(elem, obj) { boost::hash_combine(hash, BSONElement::Hasher()(elem)); } return hash; } bool BSONObj::isPrefixOf(const BSONObj& otherObj) const { BSONObjIterator a(*this); BSONObjIterator b(otherObj); while (a.more() && b.more()) { BSONElement x = a.next(); BSONElement y = b.next(); if (x != y) return false; } return !a.more(); } bool BSONObj::isFieldNamePrefixOf(const BSONObj& otherObj) const { BSONObjIterator a(*this); BSONObjIterator b(otherObj); while (a.more() && b.more()) { BSONElement x = a.next(); BSONElement y = b.next(); if (!str::equals(x.fieldName(), y.fieldName())) { return false; } } return !a.more(); } template void _getFieldsDotted(const BSONObj* obj, const StringData& name, BSONElementColl& ret, bool expandLastArray) { BSONElement e = obj->getField(name); if (e.eoo()) { size_t idx = name.find('.'); if (idx != string::npos) { StringData left = name.substr(0, idx); StringData next = name.substr(idx + 1, name.size()); BSONElement e = obj->getField(left); if (e.type() == Object) { e.embeddedObject().getFieldsDotted(next, ret, expandLastArray); } else if (e.type() == Array) { bool allDigits = false; if (next.size() > 0 && isdigit(next[0])) { unsigned temp = 1; while (temp < next.size() && isdigit(next[temp])) temp++; allDigits = temp == next.size() || next[temp] == '.'; } if (allDigits) { e.embeddedObject().getFieldsDotted(next, ret, expandLastArray); } else { BSONObjIterator i(e.embeddedObject()); while (i.more()) { BSONElement e2 = i.next(); if (e2.type() == Object || e2.type() == Array) e2.embeddedObject().getFieldsDotted(next, ret, expandLastArray); } } } else { // do nothing: no match } } } else { if (e.type() == Array && expandLastArray) { BSONObjIterator i(e.embeddedObject()); while (i.more()) ret.insert(i.next()); } else { ret.insert(e); } } } void BSONObj::getFieldsDotted(const StringData& name, BSONElementSet& ret, bool expandLastArray) const { _getFieldsDotted(this, name, ret, expandLastArray); } void BSONObj::getFieldsDotted(const StringData& name, BSONElementMSet& ret, bool expandLastArray) const { _getFieldsDotted(this, name, ret, expandLastArray); } BSONElement eooElement; BSONElement BSONObj::getFieldDottedOrArray(const char*& name) const { const char* p = strchr(name, '.'); BSONElement sub; if (p) { sub = getField(string(name, p - name)); name = p + 1; } else { sub = getField(name); name = name + strlen(name); } if (sub.eoo()) return eooElement; else if (sub.type() == Array || name[0] == '\0') return sub; else if (sub.type() == Object) return sub.embeddedObject().getFieldDottedOrArray(name); else return eooElement; } BSONObj BSONObj::extractFieldsUnDotted(const BSONObj& pattern) const { BSONObjBuilder b; BSONObjIterator i(pattern); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; BSONElement x = getField(e.fieldName()); if (!x.eoo()) b.appendAs(x, ""); } return b.obj(); } BSONObj BSONObj::extractFields(const BSONObj& pattern, bool fillWithNull) const { BSONObjBuilder b( 32); // scanandorder.h can make a zillion of these, so we start the allocation very small BSONObjIterator i(pattern); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; BSONElement x = getFieldDotted(e.fieldName()); if (!x.eoo()) b.appendAs(x, e.fieldName()); else if (fillWithNull) b.appendNull(e.fieldName()); } return b.obj(); } BSONObj BSONObj::filterFieldsUndotted(const BSONObj& filter, bool inFilter) const { BSONObjBuilder b; BSONObjIterator i(*this); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; BSONElement x = filter.getField(e.fieldName()); if ((x.eoo() && !inFilter) || (!x.eoo() && inFilter)) b.append(e); } return b.obj(); } BSONElement BSONObj::getFieldUsingIndexNames(const StringData& fieldName, const BSONObj& indexKey) const { BSONObjIterator i(indexKey); int j = 0; while (i.moreWithEOO()) { BSONElement f = i.next(); if (f.eoo()) return BSONElement(); if (f.fieldName() == fieldName) break; ++j; } BSONObjIterator k(*this); while (k.moreWithEOO()) { BSONElement g = k.next(); if (g.eoo()) return BSONElement(); if (j == 0) { return g; } --j; } return BSONElement(); } /* grab names of all the fields in this object */ int BSONObj::getFieldNames(set& fields) const { int n = 0; BSONObjIterator i(*this); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; fields.insert(e.fieldName()); n++; } return n; } /* note: addFields always adds _id even if not specified returns n added not counting _id unless requested. */ int BSONObj::addFields(BSONObj& from, set& fields) { verify(isEmpty() && !isOwned()); /* partial implementation for now... */ BSONObjBuilder b; int N = fields.size(); int n = 0; BSONObjIterator i(from); bool gotId = false; while (i.moreWithEOO()) { BSONElement e = i.next(); const char* fname = e.fieldName(); if (fields.count(fname)) { b.append(e); ++n; gotId = gotId || strcmp(fname, "_id") == 0; if (n == N && gotId) break; } else if (strcmp(fname, "_id") == 0) { b.append(e); gotId = true; if (n == N && gotId) break; } } if (n) { *this = b.obj(); } return n; } bool BSONObj::couldBeArray() const { BSONObjIterator i(*this); int index = 0; while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; // TODO: If actually important, may be able to do int->char* much faster if (strcmp(e.fieldName(), ((string)(str::stream() << index)).c_str()) != 0) return false; index++; } return true; } BSONObj BSONObj::clientReadable() const { BSONObjBuilder b; BSONObjIterator i(*this); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; switch (e.type()) { case MinKey: { BSONObjBuilder m; m.append("$minElement", 1); b.append(e.fieldName(), m.done()); break; } case MaxKey: { BSONObjBuilder m; m.append("$maxElement", 1); b.append(e.fieldName(), m.done()); break; } default: b.append(e); } } return b.obj(); } BSONObj BSONObj::replaceFieldNames(const BSONObj& names) const { BSONObjBuilder b; BSONObjIterator i(*this); BSONObjIterator j(names); BSONElement f = j.moreWithEOO() ? j.next() : BSONObj().firstElement(); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; if (!f.eoo()) { b.appendAs(e, f.fieldName()); f = j.next(); } else { b.append(e); } } return b.obj(); } Status BSONObj::_okForStorage(bool root, bool deep) const { BSONObjIterator i(*this); // The first field is special in the case of a DBRef where the first field must be $ref bool first = true; while (i.more()) { BSONElement e = i.next(); const char* name = e.fieldName(); // Cannot start with "$", unless dbref which must start with ($ref, $id) if (str::startsWith(name, '$')) { if (first && // $ref is a collection name and must be a String str::equals(name, "$ref") && e.type() == String && str::equals(i.next().fieldName(), "$id")) { first = false; // keep inspecting fields for optional "$db" e = i.next(); name = e.fieldName(); // "" if eoo() // optional $db field must be a String if (str::equals(name, "$db") && e.type() == String) { continue; // this element is fine, so continue on to siblings (if any more) } // Can't start with a "$", all other checks are done below (outside if blocks) if (str::startsWith(name, '$')) { return Status(ErrorCodes::DollarPrefixedFieldName, str::stream() << name << " is not valid for storage."); } } else { // not an okay, $ prefixed field name. return Status(ErrorCodes::DollarPrefixedFieldName, str::stream() << name << " is not valid for storage."); } } // Do not allow "." in the field name if (strchr(name, '.')) { return Status(ErrorCodes::DottedFieldName, str::stream() << name << " is not valid for storage."); } // (SERVER-9502) Do not allow storing an _id field with a RegEx type or // Array type in a root document if (root && (e.type() == RegEx || e.type() == Array || e.type() == Undefined) && str::equals(name, "_id")) { return Status(ErrorCodes::InvalidIdField, str::stream() << name << " is not valid for storage because it is of type " << typeName(e.type())); } if (deep && e.mayEncapsulate()) { switch (e.type()) { case Object: case Array: { Status s = e.embeddedObject()._okForStorage(false, true); // TODO: combine field names for better error messages if (!s.isOK()) return s; } break; case CodeWScope: { Status s = e.codeWScopeObject()._okForStorage(false, true); // TODO: combine field names for better error messages if (!s.isOK()) return s; } break; default: uassert(12579, "unhandled cases in BSONObj okForStorage", 0); } } // After we have processed one field, we are no longer on the first field first = false; } return Status::OK(); } void BSONObj::dump() const { LogstreamBuilder builder = log(); builder << hex; const char* p = objdata(); for (int i = 0; i < objsize(); i++) { builder << i << '\t' << (0xff & ((unsigned)*p)); if (*p >= 'A' && *p <= 'z') builder << '\t' << *p; builder << endl; p++; } } void BSONObj::getFields(unsigned n, const char** fieldNames, BSONElement* fields) const { BSONObjIterator i(*this); while (i.more()) { BSONElement e = i.next(); const char* p = e.fieldName(); for (unsigned i = 0; i < n; i++) { if (strcmp(p, fieldNames[i]) == 0) { fields[i] = e; break; } } } } BSONElement BSONObj::getField(const StringData& name) const { BSONObjIterator i(*this); while (i.more()) { BSONElement e = i.next(); // We know that e has a cached field length since BSONObjIterator::next internally // called BSONElement::size on the BSONElement that it returned, so it is more // efficient to re-use that information by obtaining the field name as a // StringData, which will be pre-populated with the cached length. if (name == e.fieldNameStringData()) return e; } return BSONElement(); } int BSONObj::getIntField(const StringData& name) const { BSONElement e = getField(name); return e.isNumber() ? (int)e.number() : std::numeric_limits::min(); } bool BSONObj::getBoolField(const StringData& name) const { BSONElement e = getField(name); return e.type() == Bool ? e.boolean() : false; } const char* BSONObj::getStringField(const StringData& name) const { BSONElement e = getField(name); return e.type() == String ? e.valuestr() : ""; } bool BSONObj::getObjectID(BSONElement& e) const { BSONElement f = getField("_id"); if (!f.eoo()) { e = f; return true; } return false; } BSONObj BSONObj::removeField(const StringData& name) const { BSONObjBuilder b; BSONObjIterator i(*this); while (i.more()) { BSONElement e = i.next(); const char* fname = e.fieldName(); if (name != fname) b.append(e); } return b.obj(); } std::string BSONObj::hexDump() const { std::stringstream ss; const char* d = objdata(); int size = objsize(); for (int i = 0; i < size; ++i) { ss.width(2); ss.fill('0'); ss << std::hex << (unsigned)(unsigned char)(d[i]) << std::dec; if ((d[i] >= '0' && d[i] <= '9') || (d[i] >= 'A' && d[i] <= 'z')) ss << '\'' << d[i] << '\''; if (i != size - 1) ss << ' '; } return ss.str(); } void BSONObj::elems(std::vector& v) const { BSONObjIterator i(*this); while (i.more()) v.push_back(i.next()); } void BSONObj::elems(std::list& v) const { BSONObjIterator i(*this); while (i.more()) v.push_back(i.next()); } /* return has eoo() true if no match supports "." notation to reach into embedded objects */ BSONElement BSONObj::getFieldDotted(const StringData& name) const { BSONElement e = getField(name); if (e.eoo()) { size_t dot_offset = name.find('.'); if (dot_offset != std::string::npos) { StringData left = name.substr(0, dot_offset); StringData right = name.substr(dot_offset + 1); BSONObj sub = getObjectField(left); return sub.isEmpty() ? BSONElement() : sub.getFieldDotted(right); } } return e; } BSONObj BSONObj::getObjectField(const StringData& name) const { BSONElement e = getField(name); BSONType t = e.type(); return t == Object || t == Array ? e.embeddedObject() : BSONObj(); } int BSONObj::nFields() const { int n = 0; BSONObjIterator i(*this); while (i.moreWithEOO()) { BSONElement e = i.next(); if (e.eoo()) break; n++; } return n; } std::string BSONObj::toString(bool isArray, bool full) const { if (isEmpty()) return (isArray ? "[]" : "{}"); StringBuilder s; toString(s, isArray, full); return s.str(); } void BSONObj::toString(StringBuilder& s, bool isArray, bool full, int depth) const { if (isEmpty()) { s << (isArray ? "[]" : "{}"); return; } s << (isArray ? "[ " : "{ "); BSONObjIterator i(*this); bool first = true; while (1) { massert(10327, "Object does not end with EOO", i.moreWithEOO()); BSONElement e = i.next(true); massert(10328, "Invalid element size", e.size() > 0); massert(10329, "Element too large", e.size() < (1 << 30)); int offset = (int)(e.rawdata() - this->objdata()); massert(10330, "Element extends past end of object", e.size() + offset <= this->objsize()); bool end = (e.size() + offset == this->objsize()); if (e.eoo()) { massert(10331, "EOO Before end of object", end); break; } if (first) first = false; else s << ", "; e.toString(s, !isArray, full, depth); } s << (isArray ? " ]" : " }"); } std::ostream& operator<<(std::ostream& s, const BSONObj& o) { return s << o.toString(); } StringBuilder& operator<<(StringBuilder& s, const BSONObj& o) { o.toString(s); return s; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobj.h000066400000000000000000000505501273231111400226410ustar00rootroot00000000000000// @file bsonobj.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include "mongo/bson/bsonelement.h" #include "mongo/base/data_view.h" #include "mongo/base/string_data.h" #include "mongo/bson/util/builder.h" #include "mongo/client/export_macros.h" #include "mongo/platform/atomic_word.h" #include "mongo/util/shared_buffer.h" namespace mongo { typedef std::set BSONElementSet; typedef std::multiset BSONElementMSet; /** C++ representation of a "BSON" object -- that is, an extended JSON-style object in a binary representation. See bsonspec.org. Note that BSONObj's have a smart pointer capability built in -- so you can pass them around by value. The reference counts used to implement this do not use locking, so copying and destroying BSONObj's are not thread-safe operations. BSON object format: code {}* EOO totalSize includes itself. Data: Bool: EOO: nothing follows Undefined: nothing follows OID: an OID object NumberDouble: NumberInt: String: Date: <8bytes> Regex: Object: a nested object, leading with its entire size, which terminates with EOO. Array: same as object DBRef: DBRef: a database reference: basically a collection name plus an Object ID BinData: Code: a function (not a closure): same format as String. Symbol: a language symbol (say a python symbol). same format as String. Code With Scope: \endcode */ class MONGO_CLIENT_API BSONObj { public: /** Construct an empty BSONObj -- that is, {}. */ BSONObj() { // Little endian ordering here, but that is ok regardless as BSON is spec'd to be // little endian external to the system. (i.e. the rest of the implementation of // bson, not this part, fails to support big endian) static const char kEmptyObjectPrototype[] = {/*size*/ 5, 0, 0, 0, /*eoo*/ 0}; _objdata = kEmptyObjectPrototype; } /** Construct a BSONObj from data in the proper format. * Use this constructor when something else owns bsonData's buffer */ explicit BSONObj(const char* bsonData) { init(bsonData); } explicit BSONObj(SharedBuffer ownedBuffer) : _objdata(ownedBuffer.get() ? ownedBuffer.get() : BSONObj().objdata()), _ownedBuffer(ownedBuffer.moveFrom()) {} #if __cplusplus >= 201103L /** Move construct a BSONObj */ BSONObj(BSONObj&& other) : _objdata(std::move(other._objdata)), _ownedBuffer(std::move(other._ownedBuffer)) { other._objdata = BSONObj()._objdata; // To return to an empty state. } // The explicit move constructor above will inhibit generation of the copy ctor, so // explicitly request the default implementation. /** Copy construct a BSONObj. */ BSONObj(const BSONObj&) = default; #endif /** Provide assignment semantics. We use the value taking form so that we can use copy * and swap, and consume both lvalue and rvalue references. */ BSONObj& operator=(BSONObj otherCopy) { this->swap(otherCopy); return *this; } /** Swap this BSONObj with 'other' */ void swap(BSONObj& other) { using std::swap; swap(_objdata, other._objdata); swap(_ownedBuffer, other._ownedBuffer); } /** A BSONObj can use a buffer it "owns" or one it does not. OWNED CASE If the BSONObj owns the buffer, the buffer can be shared among several BSONObj's (by assignment). In this case the buffer is basically implemented as a shared_ptr. Since BSONObj's are typically immutable, this works well. UNOWNED CASE A BSONObj can also point to BSON data in some other data structure it does not "own" or free later. For example, in a memory mapped file. In this case, it is important the original data stays in scope for as long as the BSONObj is in use. If you think the original data may go out of scope, call BSONObj::getOwned() to promote your BSONObj to having its own copy. On a BSONObj assignment, if the source is unowned, both the source and dest will have unowned pointers to the original buffer after the assignment. If you are not sure about ownership but need the buffer to last as long as the BSONObj, call getOwned(). getOwned() is a no-op if the buffer is already owned. If not already owned, a malloc and memcpy will result. Most ways to create BSONObj's create 'owned' variants. Unowned versions can be created with: (1) specifying true for the ifree parameter in the constructor (2) calling BSONObjBuilder::done(). Use BSONObjBuilder::obj() to get an owned copy (3) retrieving a subobject retrieves an unowned pointer into the parent BSON object @return true if this is in owned mode */ bool isOwned() const { return _ownedBuffer.get() != 0; } /** assure the data buffer is under the control of this BSONObj and not a remote buffer @see isOwned() */ BSONObj getOwned() const; /** @return a new full (and owned) copy of the object. */ BSONObj copy() const; /** Readable representation of a BSON object in an extended JSON-style notation. This is an abbreviated representation which might be used for logging. */ enum { maxToStringRecursionDepth = 100 }; std::string toString(bool isArray = false, bool full = false) const; void toString(StringBuilder& s, bool isArray = false, bool full = false, int depth = 0) const; /** Properly formatted JSON string. @param pretty if true we try to add some lf's and indentation */ std::string jsonString(JsonStringFormat format = Strict, int pretty = 0, bool isArray = false) const; /** note: addFields always adds _id even if not specified */ int addFields(BSONObj& from, std::set& fields); /* returns n added */ /** remove specified field and return a new object with the remaining fields. slowish as builds a full new object */ BSONObj removeField(const StringData& name) const; /** returns # of top level fields in the object note: iterates to count the fields */ int nFields() const; /** adds the field names to the fields set. does NOT clear it (appends). */ int getFieldNames(std::set& fields) const; /** @return the specified element. element.eoo() will be true if not found. @param name field to find. supports dot (".") notation to reach into embedded objects. for example "x.y" means "in the nested object in field x, retrieve field y" */ BSONElement getFieldDotted(const StringData& name) const; /** Like getFieldDotted(), but expands arrays and returns all matching objects. * Turning off expandLastArray allows you to retrieve nested array objects instead of * their contents. */ void getFieldsDotted(const StringData& name, BSONElementSet& ret, bool expandLastArray = true) const; void getFieldsDotted(const StringData& name, BSONElementMSet& ret, bool expandLastArray = true) const; /** Like getFieldDotted(), but returns first array encountered while traversing the dotted fields of name. The name variable is updated to represent field names with respect to the returned element. */ BSONElement getFieldDottedOrArray(const char*& name) const; /** Get the field of the specified name. eoo() is true on the returned element if not found. */ BSONElement getField(const StringData& name) const; /** Get several fields at once. This is faster than separate getField() calls as the size of elements iterated can then be calculated only once each. @param n number of fieldNames, and number of elements in the fields array @param fields if a field is found its element is stored in its corresponding position in this array. if not found the array element is unchanged. */ void getFields(unsigned n, const char** fieldNames, BSONElement* fields) const; /** Get the field of the specified name. eoo() is true on the returned element if not found. */ BSONElement operator[](const StringData& field) const { return getField(field); } BSONElement operator[](int field) const { StringBuilder ss; ss << field; std::string s = ss.str(); return getField(s.c_str()); } /** @return true if field exists */ bool hasField(const StringData& name) const { return !getField(name).eoo(); } /** @return true if field exists */ bool hasElement(const StringData& name) const { return hasField(name); } /** @return "" if DNE or wrong type */ const char* getStringField(const StringData& name) const; /** @return subobject of the given name */ BSONObj getObjectField(const StringData& name) const; /** @return INT_MIN if not present - does some type conversions */ int getIntField(const StringData& name) const; /** @return false if not present @see BSONElement::trueValue() */ bool getBoolField(const StringData& name) const; /** @param pattern a BSON obj indicating a set of (un-dotted) field * names. Element values are ignored. * @return a BSON obj constructed by taking the elements of this obj * that correspond to the fields in pattern. Field names of the * returned object are replaced with the empty string. If field in * pattern is missing, it is omitted from the returned object. * * Example: if this = {a : 4 , b : 5 , c : 6}) * this.extractFieldsUnDotted({a : 1 , c : 1}) -> {"" : 4 , "" : 6 } * this.extractFieldsUnDotted({b : "blah"}) -> {"" : 5} * */ BSONObj extractFieldsUnDotted(const BSONObj& pattern) const; /** extract items from object which match a pattern object. e.g., if pattern is { x : 1, y : 1 }, builds an object with x and y elements of this object, if they are present. returns elements with original field names */ BSONObj extractFields(const BSONObj& pattern, bool fillWithNull = false) const; BSONObj filterFieldsUndotted(const BSONObj& filter, bool inFilter) const; BSONElement getFieldUsingIndexNames(const StringData& fieldName, const BSONObj& indexKey) const; /** arrays are bson objects with numeric and increasing field names @return true if field names are numeric and increasing */ bool couldBeArray() const; /** @return the raw data of the object */ const char* objdata() const { return _objdata; } /** @return total size of the BSON object in bytes */ int objsize() const { return ConstDataView(objdata()).readLE(); } /** performs a cursory check on the object's size only. */ bool isValid() const { int x = objsize(); return x > 0 && x <= BSONObjMaxInternalSize; } /** @return ok if it can be stored as a valid embedded doc. * Not valid if any field name: * - contains a "." * - starts with "$" * -- unless it is a dbref ($ref/$id/[$db]/...) */ inline bool okForStorage() const { return _okForStorage(false, true).isOK(); } /** Same as above with the following extra restrictions * Not valid if: * - "_id" field is a * -- Regex * -- Array */ inline bool okForStorageAsRoot() const { return _okForStorage(true, true).isOK(); } /** * Validates that this can be stored as an embedded document * See details above in okForStorage * * If 'deep' is true then validation is done to children * * If not valid a user readable status message is returned. */ inline Status storageValidEmbedded(const bool deep = true) const { return _okForStorage(false, deep); } /** * Validates that this can be stored as a document (in a collection) * See details above in okForStorageAsRoot * * If 'deep' is true then validation is done to children * * If not valid a user readable status message is returned. */ inline Status storageValid(const bool deep = true) const { return _okForStorage(true, deep); } /** @return true if object is empty -- i.e., {} */ bool isEmpty() const { return objsize() <= 5; } void dump() const; /** Alternative output format */ std::string hexDump() const; /**wo='well ordered'. fields must be in same order in each object. Ordering is with respect to the signs of the elements and allows ascending / descending key mixing. @return <0 if l0 if l>r */ int woCompare(const BSONObj& r, const Ordering& o, bool considerFieldName = true) const; /**wo='well ordered'. fields must be in same order in each object. Ordering is with respect to the signs of the elements and allows ascending / descending key mixing. @return <0 if l0 if l>r */ int woCompare(const BSONObj& r, const BSONObj& ordering = BSONObj(), bool considerFieldName = true) const; bool operator<(const BSONObj& other) const { return woCompare(other) < 0; } bool operator<=(const BSONObj& other) const { return woCompare(other) <= 0; } bool operator>(const BSONObj& other) const { return woCompare(other) > 0; } bool operator>=(const BSONObj& other) const { return woCompare(other) >= 0; } /** * @param useDotted whether to treat sort key fields as possibly dotted and expand into them */ int woSortOrder(const BSONObj& r, const BSONObj& sortKey, bool useDotted = false) const; bool equal(const BSONObj& r) const; /** * Functor compatible with std::hash for std::unordered_{map,set} * Warning: The hash function is subject to change. Do not use in cases where hashes need * to be consistent across versions. */ struct Hasher { size_t operator()(const BSONObj& obj) const; }; /** * @param otherObj * @return true if 'this' is a prefix of otherObj- in other words if * otherObj contains the same field names and field vals in the same * order as 'this', plus optionally some additional elements. */ bool isPrefixOf(const BSONObj& otherObj) const; /** * @param otherObj * @return returns true if the list of field names in 'this' is a prefix * of the list of field names in otherObj. Similar to 'isPrefixOf', * but ignores the field values and only looks at field names. */ bool isFieldNamePrefixOf(const BSONObj& otherObj) const; /** This is "shallow equality" -- ints and doubles won't match. for a deep equality test use woCompare (which is slower). */ bool binaryEqual(const BSONObj& r) const { int os = objsize(); if (os == r.objsize()) { return (os == 0 || memcmp(objdata(), r.objdata(), os) == 0); } return false; } /** @return first field of the object */ BSONElement firstElement() const { return BSONElement(objdata() + 4); } /** faster than firstElement().fieldName() - for the first element we can easily find the * fieldname without computing the element size. */ const char* firstElementFieldName() const { const char* p = objdata() + 4; return *p == EOO ? "" : p + 1; } BSONType firstElementType() const { const char* p = objdata() + 4; return (BSONType)*p; } /** Get the _id field from the object. For good performance drivers should assure that _id is the first element of the object; however, correct operation is assured regardless. @return true if found */ bool getObjectID(BSONElement& e) const; // Return a version of this object where top level elements of types // that are not part of the bson wire protocol are replaced with // string identifier equivalents. // TODO Support conversion of element types other than min and max. BSONObj clientReadable() const; /** Return new object with the field names replaced by those in the passed object. */ BSONObj replaceFieldNames(const BSONObj& obj) const; /** true unless corrupt */ bool valid() const; bool operator==(const BSONObj& other) const { return equal(other); } bool operator!=(const BSONObj& other) const { return !operator==(other); } enum MatchType { Equality = 0, LT = 0x1, LTE = 0x3, GTE = 0x6, GT = 0x4, opIN = 0x8, // { x : { $in : [1,2,3] } } NE = 0x9, opSIZE = 0x0A, opALL = 0x0B, NIN = 0x0C, opEXISTS = 0x0D, opMOD = 0x0E, opTYPE = 0x0F, opREGEX = 0x10, opOPTIONS = 0x11, opELEM_MATCH = 0x12, opNEAR = 0x13, opWITHIN = 0x14, opMAX_DISTANCE = 0x15, opGEO_INTERSECTS = 0x16, }; /** add all elements of the object to the specified vector */ void elems(std::vector&) const; /** add all elements of the object to the specified list */ void elems(std::list&) const; friend class BSONObjIterator; typedef BSONObjIterator iterator; /** use something like this: for( BSONObj::iterator i = myObj.begin(); i.more(); ) { BSONElement e = i.next(); ... } */ BSONObjIterator begin() const; void appendSelfToBufBuilder(BufBuilder& b) const { verify(objsize()); b.appendBuf(objdata(), objsize()); } template bool coerceVector(std::vector* out) const; typedef SharedBuffer::Holder Holder; /** Given a pointer to a region of un-owned memory containing BSON data, prefixed by * sufficient space for a BSONObj::Holder object, return a BSONObj that owns the * memory. * * This class will call free(holderPrefixedData), so it must have been allocated in a way * that makes that valid. */ static BSONObj takeOwnership(char* holderPrefixedData) { return BSONObj(SharedBuffer::takeOwnership(holderPrefixedData)); } private: void _assertInvalid() const; void init(const char* data) { _objdata = data; if (!isValid()) _assertInvalid(); } /** * Validate if the element is okay to be stored in a collection, maybe as the root element * * If 'root' is true then checks against _id are made. * If 'deep' is false then do not traverse through children */ Status _okForStorage(bool root, bool deep) const; const char* _objdata; SharedBuffer _ownedBuffer; }; MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& s, const BSONObj& o); MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& s, const BSONElement& e); MONGO_CLIENT_API StringBuilder& MONGO_CLIENT_FUNC operator<<(StringBuilder& s, const BSONObj& o); MONGO_CLIENT_API StringBuilder& MONGO_CLIENT_FUNC operator<<(StringBuilder& s, const BSONElement& e); inline void swap(BSONObj& l, BSONObj& r) { l.swap(r); } struct BSONArray : BSONObj { // Don't add anything other than forwarding constructors!!! BSONArray() : BSONObj() {} explicit BSONArray(const BSONObj& obj) : BSONObj(obj) {} }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobjbuilder.cpp000066400000000000000000000216551273231111400245470ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/db/jsobj.h" #include #include "mongo/util/log.h" namespace mongo { using std::endl; using std::numeric_limits; using std::string; void BSONObjBuilder::appendMinForType(const StringData& fieldName, int t) { switch (t) { // Shared canonical types case NumberInt: case NumberDouble: case NumberLong: append(fieldName, -numeric_limits::max()); return; case Symbol: case String: append(fieldName, ""); return; case Date: // min varies with V0 and V1 indexes, so we go one type lower. appendBool(fieldName, true); // appendDate( fieldName , numeric_limits::min() ); return; case Timestamp: appendTimestamp(fieldName, Timestamp_t()); return; case Undefined: // shared with EOO appendUndefined(fieldName); return; // Separate canonical types case MinKey: appendMinKey(fieldName); return; case MaxKey: appendMaxKey(fieldName); return; case jstOID: { OID o; appendOID(fieldName, &o); return; } case Bool: appendBool(fieldName, false); return; case jstNULL: appendNull(fieldName); return; case Object: append(fieldName, BSONObj()); return; case Array: appendArray(fieldName, BSONObj()); return; case BinData: appendBinData(fieldName, 0, BinDataGeneral, (const char*)0); return; case RegEx: appendRegex(fieldName, ""); return; case DBRef: { OID o; appendDBRef(fieldName, "", o); return; } case Code: appendCode(fieldName, ""); return; case CodeWScope: appendCodeWScope(fieldName, "", BSONObj()); return; }; log() << "type not supported for appendMinElementForType: " << t << endl; uassert(10061, "type not supported for appendMinElementForType", false); } void BSONObjBuilder::appendMaxForType(const StringData& fieldName, int t) { switch (t) { // Shared canonical types case NumberInt: case NumberDouble: case NumberLong: append(fieldName, numeric_limits::max()); return; case Symbol: case String: appendMinForType(fieldName, Object); return; case Date: appendDate(fieldName, numeric_limits::max()); return; case Timestamp: { const int32_t max = numeric_limits::max(); appendTimestamp(fieldName, Timestamp_t(max, max)); return; } case Undefined: // shared with EOO appendUndefined(fieldName); return; // Separate canonical types case MinKey: appendMinKey(fieldName); return; case MaxKey: appendMaxKey(fieldName); return; case jstOID: { OID o = OID::max(); appendOID(fieldName, &o); return; } case Bool: appendBool(fieldName, true); return; case jstNULL: appendNull(fieldName); return; case Object: appendMinForType(fieldName, Array); return; case Array: appendMinForType(fieldName, BinData); return; case BinData: appendMinForType(fieldName, jstOID); return; case RegEx: appendMinForType(fieldName, DBRef); return; case DBRef: appendMinForType(fieldName, Code); return; case Code: appendMinForType(fieldName, CodeWScope); return; case CodeWScope: // This upper bound may change if a new bson type is added. appendMinForType(fieldName, MaxKey); return; } log() << "type not supported for appendMaxElementForType: " << t << endl; uassert(14853, "type not supported for appendMaxElementForType", false); } bool BSONObjBuilder::appendAsNumber(const StringData& fieldName, const string& data) { if (data.size() == 0 || data == "-" || data == ".") return false; unsigned int pos = 0; if (data[0] == '-') pos++; bool hasDec = false; for (; pos < data.size(); pos++) { if (isdigit(data[pos])) continue; if (data[pos] == '.') { if (hasDec) return false; hasDec = true; continue; } return false; } if (hasDec) { double d = atof(data.c_str()); append(fieldName, d); return true; } if (data.size() < 8) { append(fieldName, atoi(data.c_str())); return true; } try { long long num = boost::lexical_cast(data); append(fieldName, num); return true; } catch (boost::bad_lexical_cast&) { return false; } } BSONObjBuilder& BSONObjBuilder::appendDate(const StringData& fieldName, Date_t dt) { /* easy to pass a time_t to this and get a bad result. thus this warning. */ #if defined(MONGO_DEBUG_BUILD) && defined(MONGO_EXPOSE_MACROS) if (dt > 0 && dt <= 0xffffffff) { static int n; if (n++ == 0) log() << "DEV WARNING appendDate() called with a tiny (but nonzero) date" << std::endl; } #endif _b.appendNum((char)Date); _b.appendStr(fieldName); _b.appendNum(dt); return *this; } /* add all the fields from the object specified to this object */ BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) { if (!x.isEmpty()) _b.appendBuf(x.objdata() + 4, // skip over leading length x.objsize() - 5); // ignore leading length and trailing \0 return *this; } /* add all the fields from the object specified to this object if they don't exist */ BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) { std::set have; { BSONObjIterator i = iterator(); while (i.more()) have.insert(i.next().fieldName()); } BSONObjIterator it(x); while (it.more()) { BSONElement e = it.next(); if (have.count(e.fieldName())) continue; append(e); } return *this; } void BSONObjBuilder::appendKeys(const BSONObj& keyPattern, const BSONObj& values) { BSONObjIterator i(keyPattern); BSONObjIterator j(values); while (i.more() && j.more()) { appendAs(j.next(), i.next().fieldName()); } verify(!i.more()); verify(!j.more()); } BSONObjIterator BSONObjBuilder::iterator() const { const char* s = _b.buf() + _offset; const char* e = _b.buf() + _b.len(); return BSONObjIterator(s, e); } bool BSONObjBuilder::hasField(const StringData& name) const { BSONObjIterator i = iterator(); while (i.more()) if (name == i.next().fieldName()) return true; return false; } const string BSONObjBuilder::numStrs[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", }; // This is to ensure that BSONObjBuilder doesn't try to use numStrs before the strings have // been constructed I've tested just making numStrs a char[][], but the overhead of // constructing the strings each time was too high numStrsReady will be 0 until after // numStrs is initialized because it is a static variable bool BSONObjBuilder::numStrsReady = (numStrs[0].size() > 0); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobjbuilder.h000066400000000000000000000756331273231111400242210ustar00rootroot00000000000000/* bsonobjbuilder.h Classes in this file: BSONObjBuilder BSONArrayBuilder */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/base/data_cursor.h" #include "mongo/base/parse_number.h" #include "mongo/bson/bson_field.h" #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/timestamp.h" #include "mongo/client/export_macros.h" namespace mongo { #if defined(_WIN32) // warning: 'this' : used in base member initializer list #pragma warning(disable : 4355) #endif inline void checkFieldName(StringData fieldName) { uassert(0, "field name cannot contain null bytes", fieldName.find('\0') == std::string::npos); } /** Utility for creating a BSONObj. See also the BSON() and BSON_ARRAY() macros. */ class MONGO_CLIENT_API BSONObjBuilder : boost::noncopyable { public: /** @param initsize this is just a hint as to the final size of the object */ BSONObjBuilder(int initsize = 512) : _b(_buf), _buf(sizeof(BSONObj::Holder) + initsize), _offset(sizeof(BSONObj::Holder)), _s(this), _tracker(0), _doneCalled(false) { // Skip over space for a holder object at the beginning of the buffer, followed by // space for the object length. The length is filled in by _done. _b.skip(sizeof(BSONObj::Holder)); _b.skip(sizeof(int)); // Reserve space for the EOO byte. This means _done() can't fail. _b.reserveBytes(1); } /** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder * This is for more efficient adding of subobjects/arrays. See docs for * subobjStart for example. */ BSONObjBuilder(BufBuilder& baseBuilder) : _b(baseBuilder), _buf(0), _offset(baseBuilder.len()), _s(this), _tracker(0), _doneCalled(false) { // Skip over space for the object length, which is filled in by _done. We don't need a // holder since we are a sub-builder, and some parent builder has already made the // reservation. _b.skip(sizeof(int)); // Reserve space for the EOO byte. This means _done() can't fail. _b.reserveBytes(1); } BSONObjBuilder(const BSONSizeTracker& tracker) : _b(_buf), _buf(sizeof(BSONObj::Holder) + tracker.getSize()), _offset(sizeof(BSONObj::Holder)), _s(this), _tracker(const_cast(&tracker)), _doneCalled(false) { // See the comments in the first constructor for details. _b.skip(sizeof(BSONObj::Holder)); _b.skip(sizeof(int)); // Reserve space for the EOO byte. This means _done() can't fail. _b.reserveBytes(1); } ~BSONObjBuilder() { // If 'done' has not already been called, and we have a reference to an owning // BufBuilder but do not own it ourselves, then we must call _done to write in the // length. Otherwise, we own this memory and its lifetime ends with us, therefore // we can elide the write. if (!_doneCalled && _b.buf() && _buf.getSize() == 0) { _done(); } } /** add all the fields from the object specified to this object */ BSONObjBuilder& appendElements(BSONObj x); /** add all the fields from the object specified to this object if they don't exist already */ BSONObjBuilder& appendElementsUnique(BSONObj x); /** append element to the object we are building */ BSONObjBuilder& append(const BSONElement& e) { // do not append eoo, that would corrupt us. the builder auto appends when done() is called. verify(!e.eoo()); _b.appendBuf((void*)e.rawdata(), e.size()); return *this; } /** append an element but with a new name */ BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fieldName) { // do not append eoo, that would corrupt us. the builder auto appends when done() is called. verify(!e.eoo()); _b.appendNum((char)e.type()); _b.appendStr(fieldName); _b.appendBuf((void*)e.value(), e.valuesize()); return *this; } /** add a subobject as a member */ BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) { checkFieldName(fieldName); _b.appendNum((char)Object); _b.appendStr(fieldName); _b.appendBuf((void*)subObj.objdata(), subObj.objsize()); return *this; } /** add a subobject as a member */ BSONObjBuilder& appendObject(const StringData& fieldName, const char* objdata, int size = 0) { checkFieldName(fieldName); verify(objdata); if (size == 0) { size = ConstDataView(objdata).readLE(); } verify(size > 4 && size < 100000000); _b.appendNum((char)Object); _b.appendStr(fieldName); _b.appendBuf((void*)objdata, size); return *this; } /** add header for a new subobject and return bufbuilder for writing to * the subobject's body * * example: * * BSONObjBuilder b; * BSONObjBuilder sub (b.subobjStart("fieldName")); * // use sub * sub.done() * // use b and convert to object */ BufBuilder& subobjStart(const StringData& fieldName) { checkFieldName(fieldName); _b.appendNum((char)Object); _b.appendStr(fieldName); return _b; } /** add a subobject as a member with type Array. Thus arr object should have "0", "1", ... style fields in it. */ BSONObjBuilder& appendArray(const StringData& fieldName, const BSONObj& subObj) { checkFieldName(fieldName); _b.appendNum((char)Array); _b.appendStr(fieldName); _b.appendBuf((void*)subObj.objdata(), subObj.objsize()); return *this; } BSONObjBuilder& append(const StringData& fieldName, BSONArray arr) { return appendArray(fieldName, arr); } /** add header for a new subarray and return bufbuilder for writing to the subarray's body */ BufBuilder& subarrayStart(const StringData& fieldName) { checkFieldName(fieldName); _b.appendNum((char)Array); _b.appendStr(fieldName); return _b; } /** Append a boolean element */ BSONObjBuilder& appendBool(const StringData& fieldName, int val) { checkFieldName(fieldName); _b.appendNum((char)Bool); _b.appendStr(fieldName); _b.appendNum((char)(val ? 1 : 0)); return *this; } /** Append a boolean element */ BSONObjBuilder& append(const StringData& fieldName, bool val) { checkFieldName(fieldName); _b.appendNum((char)Bool); _b.appendStr(fieldName); _b.appendNum((char)(val ? 1 : 0)); return *this; } /** Append a 32 bit integer element */ BSONObjBuilder& append(const StringData& fieldName, int n) { checkFieldName(fieldName); _b.appendNum((char)NumberInt); _b.appendStr(fieldName); _b.appendNum(n); return *this; } /** Append a 32 bit unsigned element - cast to a signed int. */ BSONObjBuilder& append(const StringData& fieldName, unsigned n) { return append(fieldName, (int)n); } /** Append a NumberLong */ BSONObjBuilder& append(const StringData& fieldName, long long n) { checkFieldName(fieldName); _b.appendNum((char)NumberLong); _b.appendStr(fieldName); _b.appendNum(n); return *this; } /** appends a number. if n < max(int)/2 then uses int, otherwise long long */ BSONObjBuilder& appendIntOrLL(const StringData& fieldName, long long n) { // extra () to avoid max macro on windows static const long long maxInt = (std::numeric_limits::max)() / 2; static const long long minInt = -maxInt; if (minInt < n && n < maxInt) { append(fieldName, static_cast(n)); } else { append(fieldName, n); } return *this; } /** * appendNumber is a series of method for appending the smallest sensible type * mostly for JS */ BSONObjBuilder& appendNumber(const StringData& fieldName, int n) { return append(fieldName, n); } BSONObjBuilder& appendNumber(const StringData& fieldName, double d) { return append(fieldName, d); } BSONObjBuilder& appendNumber(const StringData& fieldName, size_t n) { static const size_t maxInt = (1 << 30); if (n < maxInt) append(fieldName, static_cast(n)); else append(fieldName, static_cast(n)); return *this; } BSONObjBuilder& appendNumber(const StringData& fieldName, long long llNumber) { static const long long maxInt = (1LL << 30); static const long long minInt = -maxInt; static const long long maxDouble = (1LL << 40); static const long long minDouble = -maxDouble; if (minInt < llNumber && llNumber < maxInt) { append(fieldName, static_cast(llNumber)); } else if (minDouble < llNumber && llNumber < maxDouble) { append(fieldName, static_cast(llNumber)); } else { append(fieldName, llNumber); } return *this; } /** Append a double element */ BSONObjBuilder& append(const StringData& fieldName, double n) { checkFieldName(fieldName); _b.appendNum((char)NumberDouble); _b.appendStr(fieldName); _b.appendNum(n); return *this; } /** tries to append the data as a number * @return true if the data was able to be converted to a number */ bool appendAsNumber(const StringData& fieldName, const std::string& data); /** Append a BSON Object ID (OID type). @deprecated Generally, it is preferred to use the append append(name, oid) method for this. */ BSONObjBuilder& appendOID(const StringData& fieldName, OID* oid = 0, bool generateIfBlank = false) { checkFieldName(fieldName); _b.appendNum((char)jstOID); _b.appendStr(fieldName); if (oid) _b.appendBuf(oid->view().view(), OID::kOIDSize); else { OID tmp; if (generateIfBlank) tmp.init(); else tmp.clear(); _b.appendBuf(tmp.view().view(), OID::kOIDSize); } return *this; } /** Append a BSON Object ID. @param fieldName Field name, e.g., "_id". @returns the builder object */ BSONObjBuilder& append(const StringData& fieldName, OID oid) { checkFieldName(fieldName); _b.appendNum((char)jstOID); _b.appendStr(fieldName); _b.appendBuf(oid.view().view(), OID::kOIDSize); return *this; } /** Generate and assign an object id for the _id field. _id should be the first element in the object for good performance. */ BSONObjBuilder& genOID() { return append("_id", OID::gen()); } /** Append a time_t date. @param dt a C-style 32 bit date value, that is the number of seconds since January 1, 1970, 00:00:00 GMT */ BSONObjBuilder& appendTimeT(const StringData& fieldName, time_t dt) { checkFieldName(fieldName); _b.appendNum((char)Date); _b.appendStr(fieldName); _b.appendNum(static_cast(dt) * 1000); return *this; } /** Append a date. @param dt a Java-style 64 bit date value, that is the number of milliseconds since January 1, 1970, 00:00:00 GMT */ BSONObjBuilder& appendDate(const StringData& fieldName, Date_t dt); BSONObjBuilder& append(const StringData& fieldName, Date_t dt) { return appendDate(fieldName, dt); } /** Append a regular expression value @param regex the regular expression pattern @param regex options such as "i" or "g" */ BSONObjBuilder& appendRegex(const StringData& fieldName, const StringData& regex, const StringData& options = "") { checkFieldName(fieldName); uassert(0, "regex cannot contain null bytes", regex.find('\0') == std::string::npos); _b.appendNum((char)RegEx); _b.appendStr(fieldName); _b.appendStr(regex); _b.appendStr(options); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONRegEx& regex) { return appendRegex(fieldName, regex.pattern, regex.flags); } BSONObjBuilder& appendCode(const StringData& fieldName, const StringData& code) { checkFieldName(fieldName); _b.appendNum((char)Code); _b.appendStr(fieldName); _b.appendNum((int)code.size() + 1); _b.appendStr(code); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONCode& code) { return appendCode(fieldName, code.code); } /** Append a string element. @param sz size includes terminating null character */ BSONObjBuilder& append(const StringData& fieldName, const char* str, int sz) { checkFieldName(fieldName); _b.appendNum((char)String); _b.appendStr(fieldName); _b.appendNum((int)sz); _b.appendBuf(str, sz); return *this; } /** Append a string element */ BSONObjBuilder& append(const StringData& fieldName, const char* str) { return append(fieldName, str, (int)strlen(str) + 1); } /** Append a string element */ BSONObjBuilder& append(const StringData& fieldName, const std::string& str) { return append(fieldName, str.c_str(), (int)str.size() + 1); } /** Append a string element */ BSONObjBuilder& append(const StringData& fieldName, const StringData& str) { checkFieldName(fieldName); _b.appendNum((char)String); _b.appendStr(fieldName); _b.appendNum((int)str.size() + 1); _b.appendStr(str, true); return *this; } BSONObjBuilder& appendSymbol(const StringData& fieldName, const StringData& symbol) { checkFieldName(fieldName); _b.appendNum((char)Symbol); _b.appendStr(fieldName); _b.appendNum((int)symbol.size() + 1); _b.appendStr(symbol); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONSymbol& symbol) { return appendSymbol(fieldName, symbol.symbol); } /** Implements builder interface but no-op in ObjBuilder */ void appendNull() { msgasserted(16234, "Invalid call to appendNull in BSONObj Builder."); } /** Append a Null element to the object */ BSONObjBuilder& appendNull(const StringData& fieldName) { checkFieldName(fieldName); _b.appendNum((char)jstNULL); _b.appendStr(fieldName); return *this; } // Append an element that is less than all other keys. BSONObjBuilder& appendMinKey(const StringData& fieldName) { checkFieldName(fieldName); _b.appendNum((char)MinKey); _b.appendStr(fieldName); return *this; } // Append an element that is greater than all other keys. BSONObjBuilder& appendMaxKey(const StringData& fieldName) { checkFieldName(fieldName); _b.appendNum((char)MaxKey); _b.appendStr(fieldName); return *this; } /** Append a Timestamp element to the object */ BSONObjBuilder& appendTimestamp(const StringData& fieldName, const Timestamp_t& ts = Timestamp_t()) { checkFieldName(fieldName); _b.appendNum((char)Timestamp); _b.appendStr(fieldName); char buf[2 * sizeof(uint32_t)]; DataCursor cur(buf); cur.writeLEAndAdvance<>(ts.increment()); cur.writeLEAndAdvance<>(ts.seconds()); _b.appendBuf(buf, sizeof(buf)); return *this; } BSONObjBuilder& append(const StringData& fieldName, const Timestamp_t& ts) { return appendTimestamp(fieldName, ts); } /* Append an element of the deprecated DBRef type. @deprecated */ BSONObjBuilder& appendDBRef(const StringData& fieldName, const StringData& ns, const OID& oid) { checkFieldName(fieldName); _b.appendNum((char)DBRef); _b.appendStr(fieldName); _b.appendNum((int)ns.size() + 1); _b.appendStr(ns); _b.appendBuf(oid.view().view(), OID::kOIDSize); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONDBRef& dbref) { return appendDBRef(fieldName, dbref.ns, dbref.oid); } /** Append a binary data element @param fieldName name of the field @param len length of the binary data in bytes @param subtype subtype information for the data. @see enum BinDataType in bsontypes.h. Use BinDataGeneral if you don't care about the type. @param data the byte array */ BSONObjBuilder& appendBinData(const StringData& fieldName, int len, BinDataType type, const void* data) { checkFieldName(fieldName); _b.appendNum((char)BinData); _b.appendStr(fieldName); _b.appendNum(len); _b.appendNum((char)type); _b.appendBuf(data, len); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONBinData& bd) { return appendBinData(fieldName, bd.length, bd.type, bd.data); } /** Subtype 2 is deprecated. Append a BSON bindata bytearray element. @param data a byte array @param len the length of data */ BSONObjBuilder& appendBinDataArrayDeprecated(const char* fieldName, const void* data, int len) { checkFieldName(fieldName); _b.appendNum((char)BinData); _b.appendStr(fieldName); _b.appendNum(len + 4); _b.appendNum((char)0x2); _b.appendNum(len); _b.appendBuf(data, len); return *this; } /** Append to the BSON object a field of type CodeWScope. This is a javascript code fragment accompanied by some scope that goes with it. */ BSONObjBuilder& appendCodeWScope(const StringData& fieldName, const StringData& code, const BSONObj& scope) { checkFieldName(fieldName); _b.appendNum((char)CodeWScope); _b.appendStr(fieldName); _b.appendNum((int)(4 + 4 + code.size() + 1 + scope.objsize())); _b.appendNum((int)code.size() + 1); _b.appendStr(code); _b.appendBuf((void*)scope.objdata(), scope.objsize()); return *this; } BSONObjBuilder& append(const StringData& fieldName, const BSONCodeWScope& cws) { return appendCodeWScope(fieldName, cws.code, cws.scope); } void appendUndefined(const StringData& fieldName) { _b.appendNum((char)Undefined); _b.appendStr(fieldName); } /* helper function -- see Query::where() for primary way to do this. */ void appendWhere(const StringData& code, const BSONObj& scope) { appendCodeWScope("$where", code, scope); } /** these are the min/max when comparing, not strict min/max elements for a given type */ void appendMinForType(const StringData& fieldName, int type); void appendMaxForType(const StringData& fieldName, int type); /** Append an array of values. */ template BSONObjBuilder& append(const StringData& fieldName, const std::vector& vals); template BSONObjBuilder& append(const StringData& fieldName, const std::list& vals); /** Append a set of values. */ template BSONObjBuilder& append(const StringData& fieldName, const std::set& vals); /** * Append a map of values as a sub-object. * Note: the keys of the map should be StringData-compatible (i.e. strings). */ template BSONObjBuilder& append(const StringData& fieldName, const std::map& vals); /** * destructive * The returned BSONObj will free the buffer when it is finished. * @return owned BSONObj */ BSONObj obj() { massert(10335, "builder does not own memory", owned()); doneFast(); char* buf = _b.buf(); decouple(); return BSONObj::takeOwnership(buf); } /** Fetch the object we have built. BSONObjBuilder still frees the object when the builder goes out of scope -- very important to keep in mind. Use obj() if you would like the BSONObj to last longer than the builder. */ BSONObj done() { return BSONObj(_done()); } // Like 'done' above, but does not construct a BSONObj to return to the caller. void doneFast() { (void)_done(); } /** Peek at what is in the builder, but leave the builder ready for more appends. The returned object is only valid until the next modification or destruction of the builder. Intended use case: append a field if not already there. */ BSONObj asTempObj() { BSONObj temp(_done()); _b.setlen(_b.len() - 1); // next append should overwrite the EOO _b.reserveBytes(1); // Rereserve room for the real EOO _doneCalled = false; return temp; } /** Make it look as if "done" has been called, so that our destructor is a no-op. Do * this if you know that you don't care about the contents of the builder you are * destroying. * * Note that it is invalid to call any method other than the destructor after invoking * this method. */ void abandon() { _doneCalled = true; } void decouple() { _b.decouple(); // post done() call version. be sure jsobj frees... } void appendKeys(const BSONObj& keyPattern, const BSONObj& values); static std::string MONGO_CLIENT_FUNC numStr(int i) { if (i >= 0 && i < 100 && numStrsReady) return numStrs[i]; StringBuilder o; o << i; return o.str(); } /** Stream oriented way to add field names and values. */ BSONObjBuilderValueStream& operator<<(const StringData& name) { _s.endField(name); return _s; } /** Stream oriented way to add field names and values. */ BSONObjBuilder& operator<<(GENOIDLabeler) { return genOID(); } Labeler operator<<(const Labeler::Label& l) { massert(10336, "No subobject started", _s.subobjStarted()); return _s << l; } template BSONObjBuilderValueStream& operator<<(const BSONField& f) { _s.endField(f.name()); return _s; } template BSONObjBuilder& operator<<(const BSONFieldValue& v) { append(v.name(), v.value()); return *this; } BSONObjBuilder& operator<<(const BSONElement& e) { append(e); return *this; } bool isArray() const { return false; } /** @return true if we are using our own bufbuilder, and not an alternate * that was given to us in our constructor */ bool owned() const { return &_b == &_buf; } BSONObjIterator iterator() const; bool hasField(const StringData& name) const; int len() const { return _b.len(); } BufBuilder& bb() { return _b; } private: char* _done() { if (_doneCalled) return _b.buf() + _offset; _doneCalled = true; // TODO remove this or find some way to prevent it from failing. Since this is intended // for use with BSON() literal queries, it is less likely to result in oversized BSON. _s.endField(); _b.claimReservedBytes(1); // Prevents adding EOO from failing. _b.appendNum((char)EOO); char* data = _b.buf() + _offset; int size = _b.len() - _offset; DataView(data).writeLE(size); if (_tracker) _tracker->got(size); return data; } BufBuilder& _b; BufBuilder _buf; int _offset; BSONObjBuilderValueStream _s; BSONSizeTracker* _tracker; bool _doneCalled; static const std::string numStrs[100]; // cache of 0 to 99 inclusive static bool numStrsReady; // for static init safety. }; class BSONArrayBuilder : boost::noncopyable { public: BSONArrayBuilder() : _i(0), _b() {} BSONArrayBuilder(BufBuilder& _b) : _i(0), _b(_b) {} BSONArrayBuilder(int initialSize) : _i(0), _b(initialSize) {} template BSONArrayBuilder& append(const T& x) { _b.append(num(), x); return *this; } BSONArrayBuilder& append(const BSONElement& e) { _b.appendAs(e, num()); return *this; } BSONArrayBuilder& operator<<(const BSONElement& e) { return append(e); } template BSONArrayBuilder& operator<<(const T& x) { _b << num().c_str() << x; return *this; } void appendNull() { _b.appendNull(num()); } void appendUndefined() { _b.appendUndefined(num()); } /** * destructive - ownership moves to returned BSONArray * @return owned BSONArray */ BSONArray arr() { return BSONArray(_b.obj()); } BSONObj obj() { return _b.obj(); } BSONObj done() { return _b.done(); } void doneFast() { _b.doneFast(); } template BSONArrayBuilder& append(const std::list& vals); template BSONArrayBuilder& append(const std::set& vals); // These two just use next position BufBuilder& subobjStart() { return _b.subobjStart(num()); } BufBuilder& subarrayStart() { return _b.subarrayStart(num()); } BSONArrayBuilder& appendRegex(const StringData& regex, const StringData& options = "") { uassert(0, "regex cannot contain null bytes", regex.find('\0') == std::string::npos); _b.appendRegex(num(), regex, options); return *this; } BSONArrayBuilder& appendBinData(int len, BinDataType type, const void* data) { _b.appendBinData(num(), len, type, data); return *this; } BSONArrayBuilder& appendCode(const StringData& code) { _b.appendCode(num(), code); return *this; } BSONArrayBuilder& appendCodeWScope(const StringData& code, const BSONObj& scope) { _b.appendCodeWScope(num(), code, scope); return *this; } BSONArrayBuilder& appendTimeT(time_t dt) { _b.appendTimeT(num(), dt); return *this; } BSONArrayBuilder& appendDate(Date_t dt) { _b.appendDate(num(), dt); return *this; } BSONArrayBuilder& appendBool(bool val) { _b.appendBool(num(), val); return *this; } bool isArray() const { return true; } int len() const { return _b.len(); } int arrSize() const { return _i; } BufBuilder& bb() { return _b.bb(); } private: std::string num() { return _b.numStr(_i++); } int _i; BSONObjBuilder _b; }; template inline BSONObjBuilder& BSONObjBuilder::append(const StringData& fieldName, const std::vector& vals) { BSONObjBuilder arrBuilder; for (unsigned int i = 0; i < vals.size(); ++i) arrBuilder.append(numStr(i), vals[i]); appendArray(fieldName, arrBuilder.done()); return *this; } template inline BSONObjBuilder& _appendIt(BSONObjBuilder& _this, const StringData& fieldName, const L& vals) { BSONObjBuilder arrBuilder; int n = 0; for (typename L::const_iterator i = vals.begin(); i != vals.end(); i++) arrBuilder.append(BSONObjBuilder::numStr(n++), *i); _this.appendArray(fieldName, arrBuilder.done()); return _this; } template inline BSONObjBuilder& BSONObjBuilder::append(const StringData& fieldName, const std::list& vals) { return _appendIt >(*this, fieldName, vals); } template inline BSONObjBuilder& BSONObjBuilder::append(const StringData& fieldName, const std::set& vals) { return _appendIt >(*this, fieldName, vals); } template inline BSONObjBuilder& BSONObjBuilder::append(const StringData& fieldName, const std::map& vals) { BSONObjBuilder bob; for (typename std::map::const_iterator i = vals.begin(); i != vals.end(); ++i) { bob.append(i->first, i->second); } append(fieldName, bob.obj()); return *this; } template inline BSONArrayBuilder& _appendArrayIt(BSONArrayBuilder& _this, const L& vals) { for (typename L::const_iterator i = vals.begin(); i != vals.end(); i++) _this.append(*i); return _this; } template inline BSONArrayBuilder& BSONArrayBuilder::append(const std::list& vals) { return _appendArrayIt >(*this, vals); } template inline BSONArrayBuilder& BSONArrayBuilder::append(const std::set& vals) { return _appendArrayIt >(*this, vals); } template inline BSONFieldValue BSONField::query(const char* q, const T& t) const { BSONObjBuilder b; b.append(q, t); return BSONFieldValue(_name, b.obj()); } // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT 6)); inline BSONObj OR(const BSONObj& a, const BSONObj& b) { return BSON("$or" << BSON_ARRAY(a << b)); } inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c) { return BSON("$or" << BSON_ARRAY(a << b << c)); } inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d) { return BSON("$or" << BSON_ARRAY(a << b << c << d)); } inline BSONObj OR( const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e) { return BSON("$or" << BSON_ARRAY(a << b << c << d << e)); } inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f) { return BSON("$or" << BSON_ARRAY(a << b << c << d << e << f)); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobjbuilder_test.cpp000066400000000000000000000232441273231111400256020ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * tests for BSONObjBuilder */ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include #include "mongo/unittest/unittest.h" namespace { using std::string; using std::stringstream; using mongo::BSONElement; using mongo::BSONObj; using mongo::BSONObjBuilder; using mongo::BSONType; const long long maxEncodableInt = (1 << 30) - 1; const long long minEncodableInt = -maxEncodableInt; const long long maxInt = (std::numeric_limits::max)(); const long long minInt = (std::numeric_limits::min)(); const long long maxEncodableDouble = (1LL << 40) - 1; const long long minEncodableDouble = -maxEncodableDouble; const long long maxDouble = (1LL << std::numeric_limits::digits) - 1; const long long minDouble = -maxDouble; const long long maxLongLong = (std::numeric_limits::max)(); const long long minLongLong = (std::numeric_limits::min)(); template void assertBSONTypeEquals(BSONType actual, BSONType expected, T value, int i) { if (expected != actual) { stringstream ss; ss << "incorrect type in bson object for " << (i + 1) << "-th test value " << value << ". actual: " << mongo::typeName(actual) << "; expected: " << mongo::typeName(expected); const string msg = ss.str(); FAIL() << msg; } } /** * current conversion ranges in append(unsigned n) * dbl/int max/min in comments refer to max/min encodable constants * 0 <= n <= uint_max -----> int */ TEST(BSONObjBuilderTest, AppendUnsignedInt) { struct { unsigned int v; BSONType t; } data[] = {{0, mongo::NumberInt}, {100, mongo::NumberInt}, {maxEncodableInt, mongo::NumberInt}, {maxEncodableInt + 1, mongo::NumberInt}, {static_cast(maxInt), mongo::NumberInt}, {static_cast(maxInt) + 1U, mongo::NumberInt}, {(std::numeric_limits::max)(), mongo::NumberInt}, {0, mongo::Undefined}}; for (int i = 0; data[i].t != mongo::Undefined; i++) { unsigned int v = data[i].v; BSONObjBuilder b; b.append("a", v); BSONObj o = b.obj(); ASSERT_EQUALS(o.nFields(), 1); BSONElement e = o.getField("a"); unsigned int n = e.numberLong(); ASSERT_EQUALS(n, v); assertBSONTypeEquals(e.type(), data[i].t, v, i); } } /** * current conversion ranges in appendIntOrLL(long long n) * dbl/int max/min in comments refer to max/min encodable constants * n < dbl_min -----> long long * dbl_min <= n < int_min -----> double * int_min <= n <= int_max -----> int * int_max < n <= dbl_max -----> double * dbl_max < n -----> long long */ TEST(BSONObjBuilderTest, AppendIntOrLL) { struct { long long v; BSONType t; } data[] = {{0, mongo::NumberInt}, {-100, mongo::NumberInt}, {100, mongo::NumberInt}, {-(maxInt / 2 - 1), mongo::NumberInt}, {maxInt / 2 - 1, mongo::NumberInt}, {-(maxInt / 2), mongo::NumberLong}, {maxInt / 2, mongo::NumberLong}, {minEncodableInt, mongo::NumberLong}, {maxEncodableInt, mongo::NumberLong}, {minEncodableInt - 1, mongo::NumberLong}, {maxEncodableInt + 1, mongo::NumberLong}, {minInt, mongo::NumberLong}, {maxInt, mongo::NumberLong}, {minInt - 1, mongo::NumberLong}, {maxInt + 1, mongo::NumberLong}, {minLongLong, mongo::NumberLong}, {maxLongLong, mongo::NumberLong}, {0, mongo::Undefined}}; for (int i = 0; data[i].t != mongo::Undefined; i++) { long long v = data[i].v; BSONObjBuilder b; b.appendIntOrLL("a", v); BSONObj o = b.obj(); ASSERT_EQUALS(o.nFields(), 1); BSONElement e = o.getField("a"); long long n = e.numberLong(); ASSERT_EQUALS(n, v); assertBSONTypeEquals(e.type(), data[i].t, v, i); } } /** * current conversion ranges in appendNumber(size_t n) * dbl/int max/min in comments refer to max/min encodable constants * 0 <= n <= int_max -----> int * int_max < n -----> long long */ TEST(BSONObjBuilderTest, AppendNumberSizeT) { struct { size_t v; BSONType t; } data[] = {{0, mongo::NumberInt}, {100, mongo::NumberInt}, {maxEncodableInt, mongo::NumberInt}, {maxEncodableInt + 1, mongo::NumberLong}, {size_t(maxInt), mongo::NumberLong}, {size_t(maxInt) + 1U, mongo::NumberLong}, {(std::numeric_limits::max)(), mongo::NumberLong}, {0, mongo::Undefined}}; for (int i = 0; data[i].t != mongo::Undefined; i++) { size_t v = data[i].v; BSONObjBuilder b; b.appendNumber("a", v); BSONObj o = b.obj(); ASSERT_EQUALS(o.nFields(), 1); BSONElement e = o.getField("a"); size_t n = e.numberLong(); ASSERT_EQUALS(n, v); assertBSONTypeEquals(e.type(), data[i].t, v, i); } } /** * current conversion ranges in appendNumber(long long n) * dbl/int max/min in comments refer to max/min encodable constants * n < dbl_min -----> long long * dbl_min <= n < int_min -----> double * int_min <= n <= int_max -----> int * int_max < n <= dbl_max -----> double * dbl_max < n -----> long long */ TEST(BSONObjBuilderTest, AppendNumberLongLong) { struct { long long v; BSONType t; } data[] = {{0, mongo::NumberInt}, {-100, mongo::NumberInt}, {100, mongo::NumberInt}, {minEncodableInt, mongo::NumberInt}, {maxEncodableInt, mongo::NumberInt}, {minEncodableInt - 1, mongo::NumberDouble}, {maxEncodableInt + 1, mongo::NumberDouble}, {minInt, mongo::NumberDouble}, {maxInt, mongo::NumberDouble}, {minInt - 1, mongo::NumberDouble}, {maxInt + 1, mongo::NumberDouble}, {minEncodableDouble, mongo::NumberDouble}, {maxEncodableDouble, mongo::NumberDouble}, {minEncodableDouble - 1, mongo::NumberLong}, {maxEncodableDouble + 1, mongo::NumberLong}, {minDouble, mongo::NumberLong}, {maxDouble, mongo::NumberLong}, {minDouble - 1, mongo::NumberLong}, {maxDouble + 1, mongo::NumberLong}, {minLongLong, mongo::NumberLong}, {maxLongLong, mongo::NumberLong}, {0, mongo::Undefined}}; for (int i = 0; data[i].t != mongo::Undefined; i++) { long long v = data[i].v; BSONObjBuilder b; b.appendNumber("a", v); BSONObj o = b.obj(); ASSERT_EQUALS(o.nFields(), 1); BSONElement e = o.getField("a"); if (data[i].t != mongo::NumberDouble) { long long n = e.numberLong(); ASSERT_EQUALS(n, v); } else { double n = e.numberDouble(); ASSERT_APPROX_EQUAL(n, static_cast(v), 0.001); } assertBSONTypeEquals(e.type(), data[i].t, v, i); } } TEST(BSONObjBuilderTest, StreamLongLongMin) { BSONObj o = BSON("a" << std::numeric_limits::min()); ASSERT_EQUALS(o.nFields(), 1); BSONElement e = o.getField("a"); long long n = e.numberLong(); ASSERT_EQUALS(n, std::numeric_limits::min()); } TEST(BSONObjBuilderTest, AppendNumberLongLongMinCompareObject) { BSONObjBuilder b; b.appendNumber("a", std::numeric_limits::min()); BSONObj o1 = b.obj(); BSONObj o2 = BSON("a" << std::numeric_limits::min()); ASSERT_EQUALS(o1, o2); } TEST(BSONObjBuilderTest, AppendMaxTimestampOpTimeConversion) { BSONObjBuilder b; b.appendMaxForType("a", mongo::Timestamp); BSONObj o1 = b.obj(); BSONElement e = o1.getField("a"); ASSERT_FALSE(e.eoo()); } TEST(BSONObjBuilderTest, AppendFieldNameContainingNullThrows) { BSONObjBuilder b; std::string middleNull("foo\0bar", 7); std::string beginNull("\0foobar", 7); std::string endNull("foobar\0", 7); ASSERT_THROWS(b.append(middleNull, "baz"), UserException); ASSERT_THROWS(b.append(beginNull, "baz"), UserException); ASSERT_THROWS(b.append(endNull, "baz"), UserException); } TEST(BSONObjBuilderTest, AppendFieldNameContainingNullIsExceptionSafe) { BSONObjBuilder b; b.append("foo", 1); b.append("bar", 2); std::string trollField("foo\0bar", 7); ASSERT_THROWS(b.append(trollField, "baz"), UserException); b.append("garply", "yoooo"); BSONObj bo = b.done(); ASSERT_TRUE(bo.valid()); } } // unnamed namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobjiterator.cpp000066400000000000000000000035621273231111400247470ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/db/jsobj.h" #include "mongo/util/stringutils.h" namespace mongo { /** Compare two bson elements, provided as const char *'s, by field name. */ class BSONIteratorSorted::ElementFieldCmp { public: ElementFieldCmp(bool isArray); bool operator()(const char* s1, const char* s2) const; private: LexNumCmp _cmp; }; BSONIteratorSorted::ElementFieldCmp::ElementFieldCmp(bool isArray) : _cmp(!isArray) {} bool BSONIteratorSorted::ElementFieldCmp::operator()(const char* s1, const char* s2) const { // Skip the type byte and compare field names. return _cmp(s1 + 1, s2 + 1); } BSONIteratorSorted::BSONIteratorSorted(const BSONObj& o, const ElementFieldCmp& cmp) { _nfields = o.nFields(); _fields = new const char* [_nfields]; int x = 0; BSONObjIterator i(o); while (i.more()) { _fields[x++] = i.next().rawdata(); verify(_fields[x - 1]); } verify(x == _nfields); std::sort(_fields, _fields + _nfields, cmp); _cur = 0; } BSONObjIteratorSorted::BSONObjIteratorSorted(const BSONObj& object) : BSONIteratorSorted(object, ElementFieldCmp(false)) {} BSONArrayIteratorSorted::BSONArrayIteratorSorted(const BSONArray& array) : BSONIteratorSorted(array, ElementFieldCmp(true)) {} } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsonobjiterator.h000066400000000000000000000114501273231111400244070ustar00rootroot00000000000000// bsonobjiterator.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include // like the ## operator but works with __LINE__ #include "mongo/bson/bsonobj.h" #include "mongo/base/disallow_copying.h" namespace mongo { /** iterator for a BSONObj Note each BSONObj ends with an EOO element: so you will get more() on an empty object, although next().eoo() will be true. The BSONObj must stay in scope for the duration of the iterator's execution. todo: we may want to make a more stl-like iterator interface for this with things like begin() and end() */ class BSONObjIterator { public: /** Create an iterator for a BSON object. */ BSONObjIterator(const BSONObj& jso) { int sz = jso.objsize(); if (MONGO_unlikely(sz == 0)) { _pos = _theend = 0; return; } _pos = jso.objdata() + 4; _theend = jso.objdata() + sz - 1; } BSONObjIterator(const char* start, const char* end) { _pos = start + 4; _theend = end - 1; } /** @return true if more elements exist to be enumerated. */ bool more() { return _pos < _theend; } /** @return true if more elements exist to be enumerated INCLUDING the EOO element which is * always at the end. */ bool moreWithEOO() { return _pos <= _theend; } /** @return the next element in the object. For the final element, element.eoo() will be true. * */ BSONElement next(bool checkEnd) { verify(_pos <= _theend); int maxLen = -1; if (checkEnd) { maxLen = _theend + 1 - _pos; verify(maxLen > 0); } BSONElement e(_pos, maxLen); int esize = e.size(maxLen); massert(16446, "BSONElement has bad size", esize > 0); _pos += esize; return e; } BSONElement next() { verify(_pos <= _theend); BSONElement e(_pos); _pos += e.size(); return e; } void operator++() { next(); } void operator++(int) { next(); } BSONElement operator*() { verify(_pos <= _theend); return BSONElement(_pos); } private: const char* _pos; const char* _theend; }; /** Base class implementing ordered iteration through BSONElements. */ class BSONIteratorSorted { MONGO_DISALLOW_COPYING(BSONIteratorSorted); public: ~BSONIteratorSorted() { verify(_fields); delete[] _fields; _fields = 0; } bool more() { return _cur < _nfields; } BSONElement next() { verify(_fields); if (_cur < _nfields) return BSONElement(_fields[_cur++]); return BSONElement(); } protected: class ElementFieldCmp; BSONIteratorSorted(const BSONObj& o, const ElementFieldCmp& cmp); private: const char** _fields; int _nfields; int _cur; }; /** Provides iteration of a BSONObj's BSONElements in lexical field order. */ class BSONObjIteratorSorted : public BSONIteratorSorted { public: BSONObjIteratorSorted(const BSONObj& object); }; /** * Provides iteration of a BSONArray's BSONElements in numeric field order. * The elements of a bson array should always be numerically ordered by field name, but this * implementation re-sorts them anyway. */ class BSONArrayIteratorSorted : public BSONIteratorSorted { public: BSONArrayIteratorSorted(const BSONArray& array); }; /** Similar to BOOST_FOREACH * * because the iterator is defined outside of the for, you must use {} around * the surrounding scope. Don't do this: * * if (foo) * BSONForEach(e, obj) * doSomething(e); * * but this is OK: * * if (foo) { * BSONForEach(e, obj) * doSomething(e); * } * */ #define BSONForEach(e, obj) \ ::mongo::BSONObjIterator BOOST_PP_CAT(it_, __LINE__)(obj); \ for (::mongo::BSONElement e; \ (BOOST_PP_CAT(it_, __LINE__).more() ? (e = BOOST_PP_CAT(it_, __LINE__).next(), true) \ : false); \ /*nothing*/) } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsontypes.cpp000066400000000000000000000040351273231111400235630ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/bson/bsontypes.h" #include "mongo/db/jsobj.h" namespace mongo { /* take a BSONType and return the name of that type as a char* */ const char* typeName(BSONType type) { switch (type) { case MinKey: return "MinKey"; case EOO: return "EOO"; case NumberDouble: return "NumberDouble"; case String: return "String"; case Object: return "Object"; case Array: return "Array"; case BinData: return "BinaryData"; case Undefined: return "Undefined"; case jstOID: return "OID"; case Bool: return "Bool"; case Date: return "Date"; case jstNULL: return "NULL"; case RegEx: return "RegEx"; case DBRef: return "DBRef"; case Code: return "Code"; case Symbol: return "Symbol"; case CodeWScope: return "CodeWScope"; case NumberInt: return "NumberInt32"; case Timestamp: return "Timestamp"; case NumberLong: return "NumberLong64"; // JSTypeMax doesn't make sense to turn into a string; overlaps with highest-valued type case MaxKey: return "MaxKey"; default: return "Invalid"; } } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/bsontypes.h000066400000000000000000000077601273231111400232400ustar00rootroot00000000000000// bsontypes.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/util/assert_util.h" namespace mongo { class BSONArrayBuilder; class BSONElement; class BSONObj; class BSONObjBuilder; class BSONObjBuilderValueStream; class BSONObjIterator; class Ordering; struct BSONArray; // empty subclass of BSONObj useful for overloading struct BSONElementCmpWithoutField; /** the complete list of valid BSON types see also bsonspec.org */ enum BSONType { /** smaller than all other types */ MinKey = -1, /** end of object */ EOO = 0, /** double precision floating point value */ NumberDouble = 1, /** character string, stored in utf8 */ String = 2, /** an embedded object */ Object = 3, /** an embedded array */ Array = 4, /** binary data */ BinData = 5, /** Undefined type */ Undefined = 6, /** ObjectId */ jstOID = 7, /** boolean type */ Bool = 8, /** date type */ Date = 9, /** null type */ jstNULL = 10, /** regular expression, a pattern with options */ RegEx = 11, /** deprecated / will be redesigned */ DBRef = 12, /** deprecated / use CodeWScope */ Code = 13, /** a programming language (e.g., Python) symbol */ Symbol = 14, /** javascript code that can execute on the database server, with SavedContext */ CodeWScope = 15, /** 32 bit signed integer */ NumberInt = 16, /** Updated to a Date with value next OpTime on insert */ Timestamp = 17, /** 64 bit integer */ NumberLong = 18, /** max type that is not MaxKey */ JSTypeMax = 18, /** larger than all other types */ MaxKey = 127 }; /** * returns the name of the argument's type */ const char* typeName(BSONType type); /* subtypes of BinData. bdtCustom and above are ones that the JS compiler understands, but are opaque to the database. */ enum BinDataType { BinDataGeneral = 0, Function = 1, ByteArrayDeprecated = 2, /* use BinGeneral instead */ bdtUUID = 3, /* deprecated */ newUUID = 4, /* language-independent UUID format across all drivers */ MD5Type = 5, bdtCustom = 128 }; /** Returns a number for where a given type falls in the sort order. * Elements with the same return value should be compared for value equality. * The return value is not a BSONType and should not be treated as one. * Note: if the order changes, indexes have to be re-built or than can be corruption */ inline int canonicalizeBSONType(BSONType type) { switch (type) { case MinKey: case MaxKey: return type; case EOO: case Undefined: return 0; case jstNULL: return 5; case NumberDouble: case NumberInt: case NumberLong: return 10; case mongo::String: case Symbol: return 15; case Object: return 20; case mongo::Array: return 25; case BinData: return 30; case jstOID: return 35; case mongo::Bool: return 40; case mongo::Date: return 45; case Timestamp: return 47; case RegEx: return 50; case DBRef: return 55; case Code: return 60; case CodeWScope: return 65; default: verify(0); return -1; } } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/inline_decls.h000066400000000000000000000016211273231111400236300ustar00rootroot00000000000000// inline_decls.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if defined(__GNUC__) #define NOINLINE_DECL __attribute__((noinline)) #define PACKED_DECL __attribute__((packed)) #elif defined(_MSC_VER) #define NOINLINE_DECL __declspec(noinline) #define PACKED_DECL #else #define NOINLINE_DECL #define PACKED_DECL #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/oid.cpp000066400000000000000000000106161273231111400223120ustar00rootroot00000000000000// @file oid.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/bson/oid.h" #include #include #include "mongo/base/init.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/platform/atomic_word.h" #include "mongo/platform/random.h" #include "mongo/util/hex.h" namespace mongo { namespace { boost::scoped_ptr counter; const std::size_t kTimestampOffset = 0; const std::size_t kInstanceUniqueOffset = kTimestampOffset + OID::kTimestampSize; const std::size_t kIncrementOffset = kInstanceUniqueOffset + OID::kInstanceUniqueSize; OID::InstanceUnique _instanceUnique; } // namespace MONGO_INITIALIZER_GENERAL(OIDGeneration, MONGO_NO_PREREQUISITES, ("default")) (InitializerContext* context) { boost::scoped_ptr entropy(SecureRandom::create()); counter.reset(new AtomicUInt32(uint32_t(entropy->nextInt64()))); _instanceUnique = OID::InstanceUnique::generate(*entropy); return Status::OK(); } OID::Increment OID::Increment::next() { uint64_t nextCtr = counter->fetchAndAdd(1); OID::Increment incr; incr.bytes[0] = uint8_t(nextCtr >> 16); incr.bytes[1] = uint8_t(nextCtr >> 8); incr.bytes[2] = uint8_t(nextCtr); return incr; } OID::InstanceUnique OID::InstanceUnique::generate(SecureRandom& entropy) { int64_t rand = entropy.nextInt64(); OID::InstanceUnique u; std::memcpy(u.bytes, &rand, kInstanceUniqueSize); return u; } void OID::setTimestamp(const OID::Timestamp timestamp) { _view().writeBE(timestamp, kTimestampOffset); } void OID::setInstanceUnique(const OID::InstanceUnique unique) { // Byte order doesn't matter here _view().writeNative(unique, kInstanceUniqueOffset); } void OID::setIncrement(const OID::Increment inc) { _view().writeNative(inc, kIncrementOffset); } OID::Timestamp OID::getTimestamp() const { return view().readBE(kTimestampOffset); } OID::InstanceUnique OID::getInstanceUnique() const { // Byte order doesn't matter here return view().readNative(kInstanceUniqueOffset); } OID::Increment OID::getIncrement() const { return view().readNative(kIncrementOffset); } void OID::hash_combine(size_t& seed) const { uint32_t v; for (int i = 0; i != kOIDSize; i += sizeof(uint32_t)) { memcpy(&v, _data + i, sizeof(uint32_t)); boost::hash_combine(seed, v); } } size_t OID::Hasher::operator()(const OID& oid) const { size_t seed = 0; oid.hash_combine(seed); return seed; } void OID::regenMachineId() { boost::scoped_ptr entropy(SecureRandom::create()); _instanceUnique = InstanceUnique::generate(*entropy); } unsigned OID::getMachineId() { uint32_t ret = 0; std::memcpy(&ret, _instanceUnique.bytes, sizeof(uint32_t)); return ret; } void OID::justForked() { regenMachineId(); } void OID::init() { // each set* method handles endianness setTimestamp(time(0)); setInstanceUnique(_instanceUnique); setIncrement(Increment::next()); } void OID::init(const std::string& s) { verify(s.size() == 24); const char* p = s.c_str(); for (std::size_t i = 0; i < kOIDSize; i++) { _data[i] = fromHex(p); p += 2; } } void OID::init(Date_t date, bool max) { setTimestamp(uint32_t(date / 1000)); uint64_t rest = max ? std::numeric_limits::max() : 0u; std::memcpy(_view().view(kInstanceUniqueOffset), &rest, kInstanceUniqueSize + kIncrementSize); } time_t OID::asTimeT() const { return getTimestamp(); } std::string OID::toString() const { return toHexLower(_data, kOIDSize); } std::string OID::toIncString() const { return toHexLower(getIncrement().bytes, kIncrementSize); } } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(bson_oid) mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/oid.h000066400000000000000000000161571273231111400217650ustar00rootroot00000000000000// oid.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/data_view.h" #include "mongo/bson/util/builder.h" #include "mongo/client/export_macros.h" #include "mongo/util/time_support.h" namespace mongo { class SecureRandom; /** * Object ID type. * BSON objects typically have an _id field for the object id. This field should be the first * member of the object when present. The OID class is a special type that is a 12 byte id which * is likely to be unique to the system. You may also use other types for _id's. * When _id field is missing from a BSON object, on an insert the database may insert one * automatically in certain circumstances. * * The BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), * in the highest order 4 bytes followed by a 5 byte value unique to this machine AND process, * followed by a 3 byte counter. * * 4 byte timestamp 5 byte process unique 3 byte counter * |<----------------->|<---------------------->|<-------------> * OID layout: [----|----|----|----|----|----|----|----|----|----|----|----] * 0 4 8 12 * * The timestamp is a big endian 4 byte signed-integer. * * The process unique is an arbitrary sequence of 5 bytes. There are no endianness concerns * since it is never interpreted as a multi-byte value. * * The counter is a big endian 3 byte unsigned integer. * * Note: The timestamp and counter are big endian (in contrast to the rest of BSON) because * we use memcmp to order OIDs, and we want to ensure an increasing order. * * Warning: You MUST call OID::justForked() after a fork(). This ensures that each process will * generate unique OIDs. */ class MONGO_CLIENT_API OID { public: /** * Functor compatible with std::hash for std::unordered_{map,set} * Warning: The hash function is subject to change. Do not use in cases where hashes need * to be consistent across versions. */ struct Hasher { size_t operator()(const OID& oid) const; }; OID() : _data() {} enum { kOIDSize = 12, kTimestampSize = 4, kInstanceUniqueSize = 5, kIncrementSize = 3 }; /** init from a 24 char hex string */ explicit OID(const std::string& s) { init(s); } /** init from a reference to a 12-byte array */ explicit OID(const unsigned char(&arr)[kOIDSize]) { std::memcpy(_data, arr, sizeof(arr)); } /** initialize to 'null' */ void clear() { std::memset(_data, 0, kOIDSize); } int compare(const OID& other) const { return memcmp(_data, other._data, kOIDSize); } /** @return the object ID output as 24 hex digits */ std::string toString() const; /** @return the random/sequential part of the object ID as 6 hex digits */ std::string toIncString() const; static OID MONGO_CLIENT_FUNC gen() { OID o((no_initialize_tag())); o.init(); return o; } // Caller must ensure that the buffer is valid for kOIDSize bytes. // this is templated because some places use unsigned char vs signed char template static OID MONGO_CLIENT_FUNC from(T* buf) { OID o((no_initialize_tag())); std::memcpy(o._data, buf, OID::kOIDSize); return o; } static OID MONGO_CLIENT_FUNC max() { OID o((no_initialize_tag())); std::memset(o._data, 0xFF, kOIDSize); return o; } /** sets the contents to a new oid / randomized value */ void init(); /** init from a 24 char hex string */ void init(const std::string& s); /** Set to the min/max OID that could be generated at given timestamp. */ void init(Date_t date, bool max = false); time_t asTimeT() const; Date_t asDateT() const { return asTimeT() * 1000LL; } // True iff the OID is not empty bool isSet() const { return compare(OID()) != 0; } /** * this is not consistent * do not store on disk */ void hash_combine(size_t& seed) const; /** call this after a fork to update the process id */ static void MONGO_CLIENT_FUNC justForked(); static unsigned MONGO_CLIENT_FUNC getMachineId(); // used by the 'features' command static void MONGO_CLIENT_FUNC regenMachineId(); // Timestamp is 4 bytes so we just use int32_t typedef int32_t Timestamp; // Wrappers so we can return stuff by value. struct InstanceUnique { static InstanceUnique MONGO_CLIENT_FUNC generate(SecureRandom& entropy); uint8_t bytes[kInstanceUniqueSize]; }; struct Increment { public: static Increment MONGO_CLIENT_FUNC next(); uint8_t bytes[kIncrementSize]; }; void setTimestamp(Timestamp timestamp); void setInstanceUnique(InstanceUnique unique); void setIncrement(Increment inc); Timestamp getTimestamp() const; InstanceUnique getInstanceUnique() const; Increment getIncrement() const; ConstDataView view() const { return ConstDataView(_data); } private: // Internal mutable view DataView _view() { return DataView(_data); } // When we are going to immediately overwrite the bytes, there is no point in zero // initializing the data first. struct no_initialize_tag {}; explicit OID(no_initialize_tag) {} char _data[kOIDSize]; }; MONGO_CLIENT_API inline std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& s, const OID& o) { return (s << o.toString()); } MONGO_CLIENT_API inline StringBuilder& MONGO_CLIENT_FUNC operator<<(StringBuilder& s, const OID& o) { return (s << o.toString()); } /** Formatting mode for generating JSON from BSON. See for details. */ enum JsonStringFormat { /** strict RFC format */ Strict, /** 10gen format, which is close to JS format. This form is understandable by javascript running inside the Mongo server via eval() */ TenGen, /** Javascript JSON compatible */ JS }; MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator==(const OID& lhs, const OID& rhs) { return lhs.compare(rhs) == 0; } MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator!=(const OID& lhs, const OID& rhs) { return lhs.compare(rhs) != 0; } MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator<(const OID& lhs, const OID& rhs) { return lhs.compare(rhs) < 0; } MONGO_CLIENT_API inline bool MONGO_CLIENT_FUNC operator<=(const OID& lhs, const OID& rhs) { return lhs.compare(rhs) <= 0; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/oid_test.cpp000066400000000000000000000071301273231111400233460ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/bson/oid.h" #include "mongo/platform/endian.h" #include "mongo/unittest/unittest.h" namespace { using mongo::OID; TEST(Equals, Simple) { OID o1 = OID::gen(); ASSERT_EQUALS(o1, o1); ASSERT_TRUE(o1 == o1); ASSERT_EQUALS(o1.compare(o1), 0); } TEST(NotEquals, Simple) { OID o1 = OID::gen(); OID o2 = OID::gen(); ASSERT_FALSE(o1 == o2); ASSERT_TRUE(o1 != o2); ASSERT_NOT_EQUALS(o1.compare(o2), 0); } TEST(Increasing, Simple) { OID o1 = OID::gen(); OID o2 = OID::gen(); ASSERT_TRUE(o1 < o2); } TEST(IsSet, Simple) { OID o; ASSERT_FALSE(o.isSet()); o.init(); ASSERT_TRUE(o.isSet()); } TEST(JustForked, Simple) { OID o1 = OID::gen(); OID::justForked(); OID o2 = OID::gen(); ASSERT_TRUE(std::memcmp(o1.getInstanceUnique().bytes, o2.getInstanceUnique().bytes, OID::kInstanceUniqueSize) != 0); } TEST(TimestampIsBigEndian, Endianness) { OID o1; // zeroed OID::Timestamp ts = 123; o1.setTimestamp(ts); int32_t ts_big = mongo::endian::nativeToBig(123); const char* oidBytes = o1.view().view(); ASSERT(std::memcmp(&ts_big, oidBytes, sizeof(int32_t)) == 0); } TEST(IncrementIsBigEndian, Endianness) { OID o1; // zeroed OID::Increment incr; // Increment is a 3 byte counter big endian incr.bytes[0] = 0xBEu; incr.bytes[1] = 0xADu; incr.bytes[2] = 0xDEu; o1.setIncrement(incr); const char* oidBytes = o1.view().view(); oidBytes += OID::kTimestampSize + OID::kInstanceUniqueSize; // now at start of increment ASSERT_EQUALS(uint8_t(oidBytes[0]), 0xBEu); ASSERT_EQUALS(uint8_t(oidBytes[1]), 0xADu); ASSERT_EQUALS(uint8_t(oidBytes[2]), 0xDEu); } TEST(Basic, Deserialize) { uint8_t OIDbytes[] = { 0xDEu, 0xADu, 0xBEu, 0xEFu, // timestamp is -559038737 (signed) 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, // unique is 0 0x11u, 0x22u, 0x33u // increment is 1122867 }; OID o1 = OID::from(OIDbytes); ASSERT_EQUALS(o1.getTimestamp(), -559038737); OID::InstanceUnique u = o1.getInstanceUnique(); for (std::size_t i = 0; i < OID::kInstanceUniqueSize; ++i) { ASSERT_EQUALS(u.bytes[i], 0x00u); } OID::Increment i = o1.getIncrement(); // construct a uint32_t from increment // recall that i is a big-endian 3 byte unsigned integer uint32_t incr = ((uint32_t(i.bytes[0]) << 16)) | ((uint32_t(i.bytes[1]) << 8)) | uint32_t(i.bytes[2]); ASSERT_EQUALS(1122867u, incr); } TEST(Basic, FromString) { std::string oidStr("541b1a00e8a23afa832b218e"); uint8_t oidBytes[] = { 0x54u, 0x1Bu, 0x1Au, 0x00u, 0xE8u, 0xA2u, 0x3Au, 0xFAu, 0x83u, 0x2Bu, 0x21u, 0x8Eu}; ASSERT_EQUALS(OID(oidStr), OID::from(oidBytes)); } TEST(Basic, FromStringToString) { std::string fromStr("541b1a00e8a23afa832b218e"); ASSERT_EQUALS(OID(fromStr).toString(), fromStr); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/ordering.h000066400000000000000000000042051273231111400230120ustar00rootroot00000000000000// ordering.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjiterator.h" namespace mongo { // todo: ideally move to db/ instead of bson/, but elim any dependencies first /** A precomputation of a BSON index or sort key pattern. That is something like: { a : 1, b : -1 } The constructor is private to make conversion more explicit so we notice where we call make(). Over time we should push this up higher and higher. */ class Ordering { unsigned bits; Ordering(unsigned b) : bits(b) {} public: Ordering(const Ordering& r) : bits(r.bits) {} void operator=(const Ordering& r) { bits = r.bits; } /** so, for key pattern { a : 1, b : -1 } get(0) == 1 get(1) == -1 */ int get(int i) const { return ((1 << i) & bits) ? -1 : 1; } // for woCompare... unsigned descending(unsigned mask) const { return bits & mask; } /*operator std::string() const { StringBuilder buf; for ( unsigned i=0; i 0 ? "+" : "-" ); return buf.str(); }*/ static Ordering make(const BSONObj& obj) { unsigned b = 0; BSONObjIterator k(obj); unsigned n = 0; while (1) { BSONElement e = k.next(); if (e.eoo()) break; uassert(13103, "too many compound keys", n <= 31); if (e.number() < 0) b |= (1 << n); n++; } return Ordering(b); } }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/timestamp.h000066400000000000000000000021331273231111400232020ustar00rootroot00000000000000/* * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/platform/cstdint.h" namespace mongo { class Timestamp_t { public: Timestamp_t() : _seconds(), _increment() {} Timestamp_t(const uint32_t seconds, const uint32_t increment) : _seconds(seconds), _increment(increment) {} uint32_t seconds() const { return _seconds; } uint32_t increment() const { return _increment; } private: const uint32_t _seconds; const uint32_t _increment; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/000077500000000000000000000000001273231111400220045ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/bson_extract.cpp000066400000000000000000000142201273231111400252020ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/bson/util/bson_extract.h" #include "mongo/db/jsobj.h" #include "mongo/util/mongoutils/str.h" namespace mongo { Status bsonExtractField(const BSONObj& object, const StringData& fieldName, BSONElement* outElement) { BSONElement element = object.getField(fieldName); if (element.eoo()) return Status(ErrorCodes::NoSuchKey, mongoutils::str::stream() << "Missing expected field \"" << fieldName.toString() << "\""); *outElement = element; return Status::OK(); } Status bsonExtractTypedField(const BSONObj& object, const StringData& fieldName, BSONType type, BSONElement* outElement) { Status status = bsonExtractField(object, fieldName, outElement); if (!status.isOK()) return status; if (type != outElement->type()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "\"" << fieldName << "\" had the wrong type. Expected " << typeName(type) << ", found " << typeName(outElement->type())); } return Status::OK(); } Status bsonExtractBooleanField(const BSONObj& object, const StringData& fieldName, bool* out) { BSONElement element; Status status = bsonExtractTypedField(object, fieldName, Bool, &element); if (!status.isOK()) return status; *out = element.boolean(); return Status::OK(); } Status bsonExtractBooleanFieldWithDefault(const BSONObj& object, const StringData& fieldName, bool defaultValue, bool* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue; return Status::OK(); } else if (!status.isOK()) { return status; } else if (!value.isNumber() && !value.isBoolean()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected boolean or number type for field \"" << fieldName << "\", found " << typeName(value.type())); } else { *out = value.trueValue(); return Status::OK(); } } Status bsonExtractStringField(const BSONObj& object, const StringData& fieldName, std::string* out) { BSONElement element; Status status = bsonExtractTypedField(object, fieldName, String, &element); if (!status.isOK()) return status; *out = element.str(); return Status::OK(); } Status bsonExtractOIDField(const BSONObj& object, const StringData& fieldName, OID* out) { BSONElement element; Status status = bsonExtractTypedField(object, fieldName, jstOID, &element); if (!status.isOK()) return status; *out = element.OID(); return Status::OK(); } Status bsonExtractOIDFieldWithDefault(const BSONObj& object, const StringData& fieldName, const OID& defaultValue, OID* out) { Status status = bsonExtractOIDField(object, fieldName, out); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue; } else if (!status.isOK()) { return status; } return Status::OK(); } Status bsonExtractStringFieldWithDefault(const BSONObj& object, const StringData& fieldName, const StringData& defaultValue, std::string* out) { Status status = bsonExtractStringField(object, fieldName, out); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue.toString(); } else if (!status.isOK()) { return status; } return Status::OK(); } Status bsonExtractIntegerField(const BSONObj& object, const StringData& fieldName, long long* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (!status.isOK()) return status; if (!value.isNumber()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have numeric type, but found " << typeName(value.type())); } long long result = value.safeNumberLong(); if (result != value.numberDouble()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have a value " "exactly representable as a 64-bit integer, but found " << value); } *out = result; return Status::OK(); } Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, const StringData& fieldName, long long defaultValue, long long* out) { Status status = bsonExtractIntegerField(object, fieldName, out); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue; status = Status::OK(); } return status; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/bson_extract.h000066400000000000000000000156051273231111400246570ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/bson/bsontypes.h" namespace mongo { class BSONObj; class BSONElement; class OID; /** * Finds an element named "fieldName" in "object". * * Returns Status::OK() and sets "*outElement" to the found element on success. Returns * ErrorCodes::NoSuchKey if there are no matches. */ Status bsonExtractField(const BSONObj& object, const StringData& fieldName, BSONElement* outElement); /** * Finds an element named "fieldName" in "object". * * Returns Status::OK() and sets *outElement to the found element on success. Returns * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch * if the type of the matching element is not "type". For return values other than * Status::OK(), the resulting value of "*outElement" is undefined. */ Status bsonExtractTypedField(const BSONObj& object, const StringData& fieldName, BSONType type, BSONElement* outElement); /** * Finds a bool-like element named "fieldName" in "object". * * Returns Status::OK() and sets *out to the found element's boolean value on success. Returns * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch * if the type of the matching element is not Bool or a number type. For return values other * than Status::OK(), the resulting value of "*out" is undefined. */ Status bsonExtractBooleanField(const BSONObj& object, const StringData& fieldName, bool* out); /** * Finds an element named "fieldName" in "object" that represents an integral value. * * Returns Status::OK() and sets *out to the element's 64-bit integer value representation on * success. Returns ErrorCodes::NoSuchKey if there are no matches for "fieldName". Returns * ErrorCodes::TypeMismatch if the value of the matching element is not of a numeric type. * Returns ErrorCodes::BadValue if the value does not have an exact 64-bit integer * representation. For return values other than Status::OK(), the resulting value of "*out" is * undefined. */ Status bsonExtractIntegerField(const BSONObj& object, const StringData& fieldName, long long* out); /** * Finds a string-typed element named "fieldName" in "object" and stores its value in "out". * * Returns Status::OK() and sets *out to the found element's string value on success. Returns * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch * if the type of the matching element is not String. For return values other than * Status::OK(), the resulting value of "*out" is undefined. */ Status bsonExtractStringField(const BSONObj& object, const StringData& fieldName, std::string* out); /** * Finds an OID-typed element named "fieldName" in "object" and stores its value in "out". * * Returns Status::OK() and sets *out to the found element's OID value on success. Returns * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch * if the type of the matching element is not OID. For return values other than Status::OK(), * the resulting value of "*out" is undefined. */ Status bsonExtractOIDField(const BSONObj& object, const StringData& fieldName, OID* out); /** * Finds a bool-like element named "fieldName" in "object". * * If a field named "fieldName" is present, and is either a number or boolean type, stores the * truth value of the field into "*out". If no field named "fieldName" is present, sets "*out" * to "defaultValue". In these cases, returns Status::OK(). * * If "fieldName" is present more than once, behavior is undefined. If the found field is not a * boolean or number, returns ErrorCodes::TypeMismatch. */ Status bsonExtractBooleanFieldWithDefault(const BSONObj& object, const StringData& fieldName, bool defaultValue, bool* out); /** * Finds an element named "fieldName" in "object" that represents an integral value. * * If a field named "fieldName" is present and is a value of numeric type with an exact 64-bit * integer representation, returns that representation in *out and returns Status::OK(). If * there is no field named "fieldName", stores defaultValue into *out and returns Status::OK(). * If the field is found, but has non-numeric type, returns ErrorCodes::TypeMismatch. If the * value has numeric type, but cannot be represented as a 64-bit integer, returns * ErrorCodes::BadValue. */ Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, const StringData& fieldName, long long defaultValue, long long* out); /** * Finds a string element named "fieldName" in "object". * * If a field named "fieldName" is present, and is a string, stores the value of the field into * "*out". If no field named fieldName is present, sets "*out" to "defaultValue". In these * cases, returns Status::OK(). * * If "fieldName" is present more than once, behavior is undefined. If the found field is not a * string, returns ErrorCodes::TypeMismatch. */ Status bsonExtractStringFieldWithDefault(const BSONObj& object, const StringData& fieldName, const StringData& defaultValue, std::string* out); /** * Finds an OID-typed element named "fieldName" in "object" and stores its value in *out. * * Returns Status::OK() and sets *out to the found element's OID value on success. If no field * named "fieldName" is present, *out is set to "defaultValue" and Status::OK() is returned. * Returns ErrorCodes::TypeMismatch if the type of the matching element is not OID. For return * values other than Status::OK(), the resulting value of *out is undefined. */ Status bsonExtractOIDFieldWithDefault(const BSONObj& object, const StringData& fieldName, const OID& defaultValue, OID* out); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/bson_extract_test.cpp000066400000000000000000000113311273231111400262410ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongo/bson/util/bson_extract.h" #include "mongo/db/jsobj.h" #include "mongo/unittest/unittest.h" using namespace mongo; TEST(ExtractBSON, ExtractField) { BSONObj obj = BSON("a" << 1 << "b" << "hello"); BSONElement element; ASSERT_OK(bsonExtractField(obj, "a", &element)); ASSERT_EQUALS(1, element.Int()); ASSERT_OK(bsonExtractField(obj, "b", &element)); ASSERT_EQUALS(std::string("hello"), element.str()); ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractField(obj, "c", &element)); } TEST(ExtractBSON, ExtractTypedField) { BSONObj obj = BSON("a" << 1 << "b" << "hello"); BSONElement element; ASSERT_OK(bsonExtractTypedField(obj, "a", NumberInt, &element)); ASSERT_EQUALS(1, element.Int()); ASSERT_OK(bsonExtractTypedField(obj, "b", String, &element)); ASSERT_EQUALS(std::string("hello"), element.str()); ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractTypedField(obj, "c", String, &element)); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractTypedField(obj, "a", String, &element)); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractTypedField(obj, "b", NumberDouble, &element)); } TEST(ExtractBSON, ExtractStringField) { BSONObj obj = BSON("a" << 1 << "b" << "hello"); std::string s; ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractStringField(obj, "a", &s)); ASSERT_OK(bsonExtractStringField(obj, "b", &s)); ASSERT_EQUALS(std::string("hello"), s); ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractStringField(obj, "c", &s)); } TEST(ExtractBSON, ExtractStringFieldWithDefault) { BSONObj obj = BSON("a" << 1 << "b" << "hello"); std::string s; ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractStringFieldWithDefault(obj, "a", "default", &s)); ASSERT_OK(bsonExtractStringFieldWithDefault(obj, "b", "default", &s)); ASSERT_EQUALS(std::string("hello"), s); ASSERT_OK(bsonExtractStringFieldWithDefault(obj, "c", "default", &s)); ASSERT_EQUALS(std::string("default"), s); } TEST(ExtractBSON, ExtractBooleanFieldWithDefault) { BSONObj obj1 = BSON("a" << 1 << "b" << "hello" << "c" << true); BSONObj obj2 = BSON("a" << 0 << "b" << "hello" << "c" << false); bool b; b = false; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj1, "a", false, &b)); ASSERT_TRUE(b); b = false; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj1, "c", false, &b)); ASSERT_TRUE(b); b = true; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj2, "a", true, &b)); ASSERT_FALSE(b); b = true; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj2, "c", true, &b)); ASSERT_FALSE(b); b = false; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj2, "d", true, &b)); ASSERT_TRUE(b); b = true; ASSERT_OK(bsonExtractBooleanFieldWithDefault(obj2, "d", false, &b)); ASSERT_FALSE(b); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractBooleanFieldWithDefault(obj1, "b", true, &b)); } TEST(ExtractBSON, ExtractIntegerField) { long long v; ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractIntegerField(BSON("a" << 1), "b", &v)); ASSERT_OK(bsonExtractIntegerFieldWithDefault(BSON("a" << 1), "b", -1LL, &v)); ASSERT_EQUALS(-1LL, v); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractIntegerField(BSON("a" << false), "a", &v)); ASSERT_EQUALS( ErrorCodes::BadValue, bsonExtractIntegerField(BSON("a" << std::numeric_limits::quiet_NaN()), "a", &v)); ASSERT_EQUALS(ErrorCodes::BadValue, bsonExtractIntegerField(BSON("a" << pow(2.0, 64)), "a", &v)); ASSERT_EQUALS(ErrorCodes::BadValue, bsonExtractIntegerField(BSON("a" << -1.5), "a", &v)); ASSERT_OK(bsonExtractIntegerField(BSON("a" << -pow(2.0, 55)), "a", &v)); ASSERT_EQUALS(-(1LL << 55), v); ASSERT_OK(bsonExtractIntegerField(BSON("a" << 5178), "a", &v)); ASSERT_EQUALS(5178, v); } mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/builder.h000066400000000000000000000277461273231111400236230ustar00rootroot00000000000000/* builder.h */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include "mongo/base/data_view.h" #include "mongo/base/string_data.h" #include "mongo/bson/inline_decls.h" #include "mongo/util/assert_util.h" namespace mongo { /* Note the limit here is rather arbitrary and is simply a standard. generally the code works with any object that fits in ram. Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive for example need to check for size too big after update $push (append) operation various db.eval() type operations */ const int BSONObjMaxUserSize = 16 * 1024 * 1024; /* Sometimes we need objects slightly larger - an object in the replication local.oplog is slightly larger than a user object for example. */ const int BSONObjMaxInternalSize = BSONObjMaxUserSize + (16 * 1024); const int BufferMaxSize = 64 * 1024 * 1024; template class StringBuilderImpl; class TrivialAllocator { public: void* Malloc(size_t sz) { return malloc(sz); } void* Realloc(void* p, size_t sz) { return realloc(p, sz); } void Free(void* p) { free(p); } }; class StackAllocator { public: enum { SZ = 512 }; void* Malloc(size_t sz) { if (sz <= SZ) return buf; return malloc(sz); } void* Realloc(void* p, size_t sz) { if (p == buf) { if (sz <= SZ) return buf; void* d = malloc(sz); if (d == 0) msgasserted(15912, "out of memory StackAllocator::Realloc"); memcpy(d, p, SZ); return d; } return realloc(p, sz); } void Free(void* p) { if (p != buf) free(p); } private: char buf[SZ]; }; template class _BufBuilder { // non-copyable, non-assignable _BufBuilder(const _BufBuilder&); _BufBuilder& operator=(const _BufBuilder&); Allocator al; public: _BufBuilder(int initsize = 512) : size(initsize) { if (size > 0) { data = (char*)al.Malloc(size); if (data == 0) msgasserted(10000, "out of memory BufBuilder"); } else { data = 0; } l = 0; reservedBytes = 0; } ~_BufBuilder() { kill(); } void kill() { if (data) { al.Free(data); data = 0; } } void reset() { l = 0; reservedBytes = 0; } void reset(int maxSize) { l = 0; reservedBytes = 0; if (maxSize && size > maxSize) { al.Free(data); data = (char*)al.Malloc(maxSize); if (data == 0) msgasserted(15913, "out of memory BufBuilder::reset"); size = maxSize; } } /** leave room for some stuff later @return point to region that was skipped. pointer may change later (on realloc), so for immediate use only */ char* skip(int n) { return grow(n); } /* note this may be deallocated (realloced) if you keep writing. */ char* buf() { return data; } const char* buf() const { return data; } /* assume ownership of the buffer - you must then free() it */ void decouple() { data = 0; } void appendUChar(unsigned char j) { BOOST_STATIC_ASSERT(CHAR_BIT == 8); appendNumImpl(j); } void appendChar(char j) { appendNumImpl(j); } void appendNum(char j) { appendNumImpl(j); } void appendNum(short j) { BOOST_STATIC_ASSERT(sizeof(short) == 2); appendNumImpl(j); } void appendNum(int j) { BOOST_STATIC_ASSERT(sizeof(int) == 4); appendNumImpl(j); } void appendNum(unsigned j) { appendNumImpl(j); } // Bool does not have a well defined encoding. #if __cplusplus >= 201103L void appendNum(bool j) = delete; #else void appendNum(bool j) { invariant(false); } #endif void appendNum(double j) { BOOST_STATIC_ASSERT(sizeof(double) == 8); appendNumImpl(j); } void appendNum(long long j) { BOOST_STATIC_ASSERT(sizeof(long long) == 8); appendNumImpl(j); } void appendNum(unsigned long long j) { appendNumImpl(j); } void appendBuf(const void* src, size_t len) { memcpy(grow((int)len), src, len); } template void appendStruct(const T& s) { appendBuf(&s, sizeof(T)); } void appendStr(const StringData& str, bool includeEndingNull = true) { const int len = str.size() + (includeEndingNull ? 1 : 0); str.copyTo(grow(len), includeEndingNull); } /** @return length of current string */ int len() const { return l; } void setlen(int newLen) { l = newLen; } /** @return size of the buffer */ int getSize() const { return size; } /* returns the pre-grow write position */ inline char* grow(int by) { int oldlen = l; int newLen = l + by; int minSize = newLen + reservedBytes; if (minSize > size) { grow_reallocate(minSize); } l = newLen; return data + oldlen; } /** * Reserve room for some number of bytes to be claimed at a later time. */ void reserveBytes(int bytes) { int minSize = l + reservedBytes + bytes; if (minSize > size) grow_reallocate(minSize); // This must happen *after* any attempt to grow. reservedBytes += bytes; } /** * Claim an earlier reservation of some number of bytes. These bytes must already have been * reserved. Appends of up to this many bytes immediately following a claim are * guaranteed to succeed without a need to reallocate. */ void claimReservedBytes(int bytes) { invariant(reservedBytes >= bytes); reservedBytes -= bytes; } private: template void appendNumImpl(T t) { // NOTE: For now, we assume that all things written // by a BufBuilder are intended for external use: either written to disk // or to the wire. Since all of our encoding formats are little endian, // we bake that assumption in here. This decision should be revisited soon. DataView(grow(sizeof(t))).writeLE(t); } /* "slow" portion of 'grow()' */ void NOINLINE_DECL grow_reallocate(int minSize) { int a = 64; while (a < minSize) a = a * 2; if (a > BufferMaxSize) { std::stringstream ss; ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit."; msgasserted(13548, ss.str().c_str()); } data = (char*)al.Realloc(data, a); if (data == NULL) msgasserted(16070, "out of memory BufBuilder::grow_reallocate"); size = a; } char* data; int l; int size; int reservedBytes; // eagerly grow_reallocate to keep this many bytes of spare room. friend class StringBuilderImpl; }; typedef _BufBuilder BufBuilder; /** The StackBufBuilder builds smaller datasets on the stack instead of using malloc. this can be significantly faster for small bufs. However, you can not decouple() the buffer with StackBufBuilder. While designed to be a variable on the stack, if you were to dynamically allocate one, nothing bad would happen. In fact in some circumstances this might make sense, say, embedded in some other object. */ class StackBufBuilder : public _BufBuilder { public: StackBufBuilder() : _BufBuilder(StackAllocator::SZ) {} void decouple(); // not allowed. not implemented. }; #if defined(_WIN32) #pragma push_macro("snprintf") #define snprintf _snprintf #endif /** std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 */ template class StringBuilderImpl { public: // Sizes are determined based on the number of characters in 64-bit + the trailing '\0' static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1; static const size_t MONGO_S32_SIZE = 12; static const size_t MONGO_U32_SIZE = 11; static const size_t MONGO_S64_SIZE = 23; static const size_t MONGO_U64_SIZE = 22; static const size_t MONGO_S16_SIZE = 7; static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix StringBuilderImpl() {} StringBuilderImpl& operator<<(double x) { return SBNUM(x, MONGO_DBL_SIZE, "%g"); } StringBuilderImpl& operator<<(int x) { return SBNUM(x, MONGO_S32_SIZE, "%d"); } StringBuilderImpl& operator<<(unsigned x) { return SBNUM(x, MONGO_U32_SIZE, "%u"); } StringBuilderImpl& operator<<(long x) { return SBNUM(x, MONGO_S64_SIZE, "%ld"); } StringBuilderImpl& operator<<(unsigned long x) { return SBNUM(x, MONGO_U64_SIZE, "%lu"); } StringBuilderImpl& operator<<(long long x) { return SBNUM(x, MONGO_S64_SIZE, "%lld"); } StringBuilderImpl& operator<<(unsigned long long x) { return SBNUM(x, MONGO_U64_SIZE, "%llu"); } StringBuilderImpl& operator<<(short x) { return SBNUM(x, MONGO_S16_SIZE, "%hd"); } StringBuilderImpl& operator<<(const void* x) { if (sizeof(x) == 8) { return SBNUM(x, MONGO_PTR_SIZE, "0x%llX"); } else { return SBNUM(x, MONGO_PTR_SIZE, "0x%lX"); } } StringBuilderImpl& operator<<(char c) { _buf.grow(1)[0] = c; return *this; } StringBuilderImpl& operator<<(const char* str) { return *this << StringData(str); } StringBuilderImpl& operator<<(const StringData& str) { append(str); return *this; } void appendDoubleNice(double x) { const int prev = _buf.l; const int maxSize = 32; char* start = _buf.grow(maxSize); int z = snprintf(start, maxSize, "%.16g", x); verify(z >= 0); verify(z < maxSize); _buf.l = prev + z; if (strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0) { write(".0", 2); } } void write(const char* buf, int len) { memcpy(_buf.grow(len), buf, len); } void append(const StringData& str) { str.copyTo(_buf.grow(str.size()), false); } void reset(int maxSize = 0) { _buf.reset(maxSize); } std::string str() const { return std::string(_buf.data, _buf.l); } /** size of current string */ int len() const { return _buf.l; } private: _BufBuilder _buf; // non-copyable, non-assignable StringBuilderImpl(const StringBuilderImpl&); StringBuilderImpl& operator=(const StringBuilderImpl&); template StringBuilderImpl& SBNUM(T val, int maxSize, const char* macro) { int prev = _buf.l; int z = snprintf(_buf.grow(maxSize), maxSize, macro, (val)); verify(z >= 0); verify(z < maxSize); _buf.l = prev + z; return *this; } }; typedef StringBuilderImpl StringBuilder; typedef StringBuilderImpl StackStringBuilder; #if defined(_WIN32) #undef snprintf #pragma pop_macro("snprintf") #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/bson/util/builder_test.cpp000066400000000000000000000030341273231111400251750ustar00rootroot00000000000000// builder_test.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/unittest/unittest.h" #include "mongo/bson/util/builder.h" namespace mongo { TEST(Builder, String1) { const char* big = "eliot was here"; StringData small(big, 5); ASSERT_EQUALS(small, "eliot"); BufBuilder bb; bb.appendStr(small); ASSERT_EQUALS(0, strcmp(bb.buf(), "eliot")); ASSERT_EQUALS(0, strcmp("eliot", bb.buf())); } TEST(Builder, StringBuilderAddress) { const void* longPtr = reinterpret_cast(-1); const void* shortPtr = reinterpret_cast(0xDEADBEEFULL); const void* nullPtr = NULL; StringBuilder sb; sb << longPtr; if (sizeof(longPtr) == 8) { ASSERT_EQUALS("0xFFFFFFFFFFFFFFFF", sb.str()); } else { ASSERT_EQUALS("0xFFFFFFFF", sb.str()); } sb.reset(); sb << shortPtr; ASSERT_EQUALS("0xDEADBEEF", sb.str()); sb.reset(); sb << nullPtr; ASSERT_EQUALS("0x0", sb.str()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/000077500000000000000000000000001273231111400213445ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/client/autolib.h000066400000000000000000000046701273231111400231630ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if defined(_MSC_VER) && !defined(LIBMONGOCLIENT_NO_AUTOLIB) # #pragma push_macro("LIBMONGOCLIENT_LIB_PREFIX") #undef LIBMONGOCLIENT_LIB_PREFIX # #pragma push_macro("LIBMONGOCLIENT_ABI_ADORNMENT") #undef LIBMONGOCLIENT_ABI_ADORNMENT # #pragma push_macro("LIBMONGOCLIENT_LIB_SUFFIX") #undef LIBMONGOCLIENT_LIB_SUFFIX # #if defined(STATIC_LIBMONGOCLIENT) #// Our static libraries start with an extra 'lib' to separate from DLLs. #define LIBMONGOCLIENT_LIB_PREFIX "lib" #if defined(_DEBUG) #if defined(_DLL) #// This is a static client lib linking to the debug DLL runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "-gd" #else #// This is a static client lib linking to the debug static runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "-sgd" #endif #else #if defined(_DLL) #// This is a static client lib linking to the retail DLL runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "" #else #// This is a static client lib linking to the retail static runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "-s" #endif #endif #else #// Our DLL doesn't have a 'lib' prefix, unlike our static lib #define LIBMONGOCLIENT_LIB_PREFIX "" #if defined(_DEBUG) #// This is a DLL libmongoclient linking to the debug DLL runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "-gd" #else #// This is a DLL libmongoclient linking to the retail DLL runtime #define LIBMONGOCLIENT_ABI_ADORNMENT "" #endif #endif # #// We always link to either the static library, or the stub for DLLs. #define LIBMONGOCLIENT_LIB_SUFFIX ".lib" # #// Tack together the pieces in the right order #pragma comment(lib, \ LIBMONGOCLIENT_LIB_PREFIX \ "mongoclient" LIBMONGOCLIENT_ABI_ADORNMENT LIBMONGOCLIENT_LIB_SUFFIX) # #pragma pop_macro("LIBMONGOCLIENT_LIB_PREFIX") #pragma pop_macro("LIBMONGOCLIENT_ABI_ADORNMENT") #pragma pop_macro("LIBMONGOCLIENT_LIB_SUFFIX") # #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_operation_builder.cpp000066400000000000000000000056221273231111400266000ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/bulk_operation_builder.h" #include #include "mongo/client/dbclientinterface.h" #include "mongo/client/insert_write_operation.h" #include "mongo/client/write_options.h" #include "mongo/client/write_result.h" namespace mongo { namespace { inline bool compare(WriteOperation* const lhs, WriteOperation* const rhs) { return lhs->operationType() > rhs->operationType(); } } // namespace BulkOperationBuilder::BulkOperationBuilder(DBClientBase* const client, const std::string& ns, bool ordered, bool bypassDocumentValidation) : _client(client), _ns(ns), _ordered(ordered), _bypassDocumentValidation(bypassDocumentValidation), _executed(false), _currentIndex(0) {} BulkOperationBuilder::~BulkOperationBuilder() { std::vector::iterator it; for (it = _write_operations.begin(); it != _write_operations.end(); ++it) delete *it; } BulkUpdateBuilder BulkOperationBuilder::find(const BSONObj& selector) { return BulkUpdateBuilder(this, selector); } void BulkOperationBuilder::insert(const BSONObj& doc) { InsertWriteOperation* insert_op = new InsertWriteOperation(doc); enqueue(insert_op); } void BulkOperationBuilder::execute(const WriteConcern* writeConcern, WriteResult* writeResult) { uassert(0, "Bulk operations cannot be re-executed", !_executed); uassert( 0, "Bulk operations cannot be executed without any operations", !_write_operations.empty()); _executed = true; if (!_ordered) std::sort(_write_operations.begin(), _write_operations.end(), compare); // This signals to the DBClientWriter that we cannot batch inserts together // over the wire protocol and must send them individually to the server in // order to understand what happened to them. writeResult->_requiresDetailedInsertResults = true; _client->_write( _ns, _write_operations, _ordered, _bypassDocumentValidation, writeConcern, writeResult); } void BulkOperationBuilder::enqueue(WriteOperation* operation) { operation->setBulkIndex(_currentIndex++); _write_operations.push_back(operation); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_operation_builder.h000066400000000000000000000077241273231111400262520ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/bson/bsonobj.h" #include "mongo/client/bulk_update_builder.h" #include "mongo/client/write_result.h" namespace mongo { class DBClientBase; class WriteConcern; class WriteOperation; /** * Class for constructing and executing bulk operations against MongoDB via a * fluent API. * * Example Usage: * * BulkOperationBuilder bulk(...); * bulk.insert(); * bulk.insert(); * bulk.find().updateOne(); * * vector results; * bulk.execute(, &results); * * Usually not instantiated directly, instead it usually comes into being via * the following DBClientBase methods: * * initializeOrderedBulkOperation() * intiializeUnorderedBulkOperation() * * The class is able to optimize unordered operations by grouping similar ones * into batches instead of sending them individually to the server. This means * that unordered writes are non-deterministic. This is by design. */ class MONGO_CLIENT_API BulkOperationBuilder { /* Enable operations of this type to append themselves to enqueue themselves */ friend class BulkUpdateBuilder; /* Enable operations of this type to append themselves to enqueue themselves */ friend class BulkUpsertBuilder; public: /** * BulkOperationBuilder constructor * * DBClientBase::initializeOrderedBulkOperation will set ordered to true * DBClientBase::initializeUnorderedBulkOperation will set ordered to false * * @param client The connection to use. * @param ns The namespace to apply the operations to. * @param ordered Whether or not ordering matters for these operations. * param bypassDocumentValidation Whether to bypass document validation for these operations, */ BulkOperationBuilder(DBClientBase* const client, const std::string& ns, bool ordered, bool bypassDocumentValidation = false); /* Deletes all of the WriteOperations that were created during the Builder's lifetime */ ~BulkOperationBuilder(); /** * Supplies a filter to select a subset of documents on which to apply an operation. * The operation that is ultimately enqueued as part of this bulk operation depends on * the subsequent method calls made to the returned BulkWriteOperation object. * * @param selector A BSONObj that describes the objects to modify. * @return BulkWriteOperation A BulkWriteOperation with the selector specified. */ BulkUpdateBuilder find(const BSONObj& selector); /** * Enqueues an insert write operation to be executed as part of the bulk operation. * * @param doc The document to enqueue. */ void insert(const BSONObj& doc); /** * Executes the bulk operation. * * @param wc The Write concern for the entire bulk operation. 0 = default (acknowledged); * @param results Vector where the results of operations will go. */ void execute(const WriteConcern* writeConcern, WriteResult* writeResult); private: void enqueue(WriteOperation* const operation); DBClientBase* const _client; const std::string _ns; const bool _ordered; const bool _bypassDocumentValidation; bool _executed; size_t _currentIndex; std::vector _write_operations; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_update_builder.cpp000066400000000000000000000051671273231111400260660ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/bulk_update_builder.h" #include "mongo/client/bulk_operation_builder.h" #include "mongo/client/delete_write_operation.h" #include "mongo/client/update_write_operation.h" #include "mongo/client/write_options.h" namespace mongo { BulkUpdateBuilder::BulkUpdateBuilder(BulkOperationBuilder* const builder, const BSONObj& selector) : _builder(builder), _selector(selector) {} void BulkUpdateBuilder::updateOne(const BSONObj& update) { uassert(0, "update object must not be empty", !update.isEmpty()); uassert(0, "update object must consist of $-prefixed modifiers", update.firstElementFieldName()[0] == '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, update, 0); _builder->enqueue(update_op); } void BulkUpdateBuilder::update(const BSONObj& update) { uassert(0, "update object must not be empty", !update.isEmpty()); uassert(0, "update object must consist of $-prefixed modifiers", update.firstElementFieldName()[0] == '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, update, UpdateOption_Multi); _builder->enqueue(update_op); } void BulkUpdateBuilder::replaceOne(const BSONObj& replacement) { if (!replacement.isEmpty()) uassert(0, "replacement object must not include $ operators", replacement.firstElementFieldName()[0] != '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, replacement, 0); _builder->enqueue(update_op); } void BulkUpdateBuilder::remove() { DeleteWriteOperation* delete_op = new DeleteWriteOperation(_selector, 0); _builder->enqueue(delete_op); } void BulkUpdateBuilder::removeOne() { DeleteWriteOperation* delete_op = new DeleteWriteOperation(_selector, RemoveOption_JustOne); _builder->enqueue(delete_op); } BulkUpsertBuilder BulkUpdateBuilder::upsert() { return BulkUpsertBuilder(_builder, _selector); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_update_builder.h000066400000000000000000000046011273231111400255230ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/bson/bsonobj.h" #include "mongo/client/bulk_upsert_builder.h" namespace mongo { class BulkOperationBuilder; /** * Class for constructing bulk write operations which have an applied filter. * * Not to be instantiated directly. Comes into being via the find() method on * BulkOperationBuilder. */ class MONGO_CLIENT_API BulkUpdateBuilder { friend class BulkOperationBuilder; public: /** * Enqueues an operation which updates a single document matching the selector by * applying the supplied update document. * * @param update The update to apply to matching documents. */ void updateOne(const BSONObj& update); /** * Enqueues an operation which updates any document matching the selector by applying * the supplied update document. * * @param update The update to apply to matching documents. */ void update(const BSONObj& update); /** * Enqueues an operation which replaces a single document matching the selector * with the supplied replacement. */ void replaceOne(const BSONObj& replacement); /** * Enqueues an operation which removes any document matching the selector. */ void remove(); /** * Enqueues an operation which removes a single document matching the selector. */ void removeOne(); /** * Specifies that this write operation will be an upsert. * * @return BulkUpsertOperation A BulkUpdateBuilder that is an upsert. */ BulkUpsertBuilder upsert(); private: BulkOperationBuilder* const _builder; const BSONObj& _selector; /* Only created by freind class BulkOperationBuilder */ BulkUpdateBuilder(BulkOperationBuilder* const builder, const BSONObj& selector); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_upsert_builder.cpp000066400000000000000000000043501273231111400261170ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/bulk_upsert_builder.h" #include "mongo/client/bulk_operation_builder.h" #include "mongo/client/update_write_operation.h" #include "mongo/client/write_options.h" namespace mongo { BulkUpsertBuilder::BulkUpsertBuilder(BulkOperationBuilder* const builder, const BSONObj& selector) : _builder(builder), _selector(selector) {} void BulkUpsertBuilder::updateOne(const BSONObj& update) { uassert(0, "update object must not be empty", !update.isEmpty()); uassert(0, "update object must consist of $-prefixed modifiers", update.firstElementFieldName()[0] == '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, update, UpdateOption_Upsert); _builder->enqueue(update_op); } void BulkUpsertBuilder::update(const BSONObj& update) { uassert(0, "update object must not be empty", !update.isEmpty()); uassert(0, "update object must consist of $-prefixed modifiers", update.firstElementFieldName()[0] == '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, update, UpdateOption_Upsert + UpdateOption_Multi); _builder->enqueue(update_op); } void BulkUpsertBuilder::replaceOne(const BSONObj& replacement) { if (!replacement.isEmpty()) uassert(0, "replacement object must not include $ operators", replacement.firstElementFieldName()[0] != '$'); UpdateWriteOperation* update_op = new UpdateWriteOperation(_selector, replacement, UpdateOption_Upsert); _builder->enqueue(update_op); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/bulk_upsert_builder.h000066400000000000000000000042351273231111400255660ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/bson/bsonobj.h" namespace mongo { class BulkOperationBuilder; /** * Class for constructing bulk write operations which have an applied filter * and are to be performed as an upsert. * * Not to be instantiated directly. Comes into being via the upsert() method on * BulkWriteOperation. */ class MONGO_CLIENT_API BulkUpsertBuilder { friend class BulkUpdateBuilder; public: /** * Enqueues an operation which updates a single document matching the selector by * applying the supplied update document. If no matching document exists, the * operation becomes an insert. * * @param update The update to apply to matching documents. */ void updateOne(const BSONObj& update); /** * Enqueues an operation which updates any document matching the selector by applying * the supplied update document. If no matching document exists, the operation * becomes an insert. * * @param update The update to apply to matching documents. */ void update(const BSONObj& update); /** * Enqueues an operation which replaces a single document matching the selector * with the supplied replacement. If no matching document exists, the operation * becomes an insert. */ void replaceOne(const BSONObj& replacement); private: BulkOperationBuilder* const _builder; const BSONObj _selector; /* Only created by friend class BulkWriteBuilder */ BulkUpsertBuilder(BulkOperationBuilder* const builder, const BSONObj& selector); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/command_writer.cpp000066400000000000000000000134121273231111400250630ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/command_writer.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/write_result.h" #include "mongo/db/namespace_string.h" namespace mongo { const int kOverhead = 8 * 1024; const char kOrderedKey[] = "ordered"; const char kBypassDocumentValidationKey[] = "bypassDocumentValidation"; CommandWriter::CommandWriter(DBClientBase* client) : _client(client) {} void CommandWriter::write(const StringData& ns, const std::vector& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult) { // Effectively a map of batch relative indexes to WriteOperations std::vector batchOps; std::vector::const_iterator batch_begin = write_operations.begin(); const std::vector::const_iterator end = write_operations.end(); while (batch_begin != end) { boost::scoped_ptr command(new BSONObjBuilder); boost::scoped_ptr batch(new BSONArrayBuilder); std::vector::const_iterator batch_iter = batch_begin; // We must be able to fit the first item of the batch. Otherwise, the calling code // passed an over size write operation in violation of our contract. invariant(_fits(batch.get(), *batch_iter)); // Set the current operation type const WriteOpType batchOpType = (*batch_iter)->operationType(); // Begin the command for this batch. (*batch_iter)->startCommand(ns.toString(), command.get()); while (true) { // Always safe to append here: either we just entered the loop, or all the // checks below passed. (*batch_iter)->appendSelfToCommand(batch.get()); // Associate batch index with WriteOperation batchOps.push_back(*batch_iter); // Peek at the next operation. const std::vector::const_iterator next = boost::next(batch_iter); // If we are out of operations, issue what we have. if (next == end) break; // If the next operation is of a different type, issue what we have. if ((*next)->operationType() != batchOpType) break; // If adding the next op would put us over the limit of ops in a batch, issue // what we have. if (std::distance(batch_begin, next) >= _client->getMaxWriteBatchSize()) break; // If we can't put the next item into the current batch, issue what we have. if (!_fits(batch.get(), *next)) break; // OK to proceed to next op. batch_iter = next; } // End the command for this batch. _endCommand(batch.get(), *batch_iter, ordered, bypassDocumentValidation, command.get()); // Issue the complete command. BSONObj batchResult = _send(command.get(), writeConcern, ns); // Merge this batch's result into the result for all batches written. writeResult->_mergeCommandResult(batchOps, batchResult); batchOps.clear(); // Check write result for errors if we are doing ordered processing or last op bool lastOp = *batch_iter == write_operations.back(); if (ordered || lastOp) writeResult->_check(lastOp); // The next batch begins with the op after the last one in the just issued batch. batch_begin = ++batch_iter; } } bool CommandWriter::_fits(BSONArrayBuilder* builder, WriteOperation* operation) { int opSize = operation->incrementalSize(); int maxSize = _client->getMaxBsonObjectSize(); // This update is too large to ever be sent as a command, assert uassert(0, "update command exceeds maxBsonObjectSize", opSize <= maxSize); return (builder->len() + opSize + kOverhead) <= maxSize; } void CommandWriter::_endCommand(BSONArrayBuilder* batch, WriteOperation* operation, bool ordered, bool bypassDocumentValidation, BSONObjBuilder* command) { command->append(operation->batchName(), batch->arr()); command->append(kOrderedKey, ordered); if (bypassDocumentValidation) { uassert(0, "bypassDocumentValidation is not supported for write operations with this server " "version.", _client->getMaxWireVersion() >= 4); command->append(kBypassDocumentValidationKey, true); } } BSONObj CommandWriter::_send(BSONObjBuilder* command, const WriteConcern* writeConcern, const StringData& ns) { command->append("writeConcern", writeConcern->obj()); BSONObj result; bool commandWorked = _client->runCommand(nsToDatabase(ns), command->obj(), result); if (!commandWorked) throw OperationException(result); return result; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/command_writer.h000066400000000000000000000031051273231111400245260ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclient_writer.h" namespace mongo { class DBClientBase; class CommandWriter : public DBClientWriter { public: explicit CommandWriter(DBClientBase* client); virtual void write(const StringData& ns, const std::vector& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult); private: void _endCommand(BSONArrayBuilder* batch, WriteOperation* op, bool ordered, bool bypassDocumentValidation, BSONObjBuilder* command); BSONObj _send(BSONObjBuilder* command, const WriteConcern* writeConcern, const StringData& ns); bool _fits(BSONArrayBuilder* builder, WriteOperation* operation); DBClientBase* const _client; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/connection_string_test.cpp000066400000000000000000000231301273231111400266330ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest.h" #include "mongo/client/dbclientinterface.h" namespace { using mongo::ConnectionString; struct URITestCase { std::string URI; std::string uname; std::string password; mongo::ConnectionString::ConnectionType type; std::string setname; size_t numservers; size_t numOptions; std::string database; }; struct InvalidURITestCase { std::string URI; }; const mongo::ConnectionString::ConnectionType kMaster = mongo::ConnectionString::MASTER; const mongo::ConnectionString::ConnectionType kSet = mongo::ConnectionString::SET; const mongo::ConnectionString::ConnectionType kPair = mongo::ConnectionString::PAIR; const URITestCase validCases[] = { {"mongodb://user:pwd@127.0.0.1", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@127.0.0.1", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://127.0.0.1/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@127.0.0.1:1234", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@127.0.0.1:1234", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://127.0.0.1:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@127.0.0.1,127.0.0.2/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@127.0.0.1,127.0.0.2/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://127.0.0.1,127.0.0.2/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@127.0.0.1:1234,127.0.0.2:1234/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@127.0.0.1:1234,127.0.0.2:1234/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://127.0.0.1:1234,127.0.0.1:1234/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@[::1],127.0.0.2/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://[::1],127.0.0.2/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@[::1]:1234,127.0.0.2:1234/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@[::1]:1234,127.0.0.2:1234/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://[::1]:1234,[::1]:1234/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@[::1]", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@[::1]", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://[::1]/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@[::1]:1234", "user", "pwd", kMaster, "", 1, 0, ""}, {"mongodb://user@[::1]:1234", "user", "", kMaster, "", 1, 0, ""}, {"mongodb://[::1]:1234/dbName?foo=a&c=b", "", "", kMaster, "", 1, 2, "dbName"}, {"mongodb://user:pwd@[::1],127.0.0.2/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@[::1],127.0.0.2/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://[::1],127.0.0.2/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@[::1]:1234,127.0.0.2:1234/?replicaSet=replName", "user", "pwd", kSet, "replName", 2, 1, ""}, {"mongodb://user@[::1]:1234,127.0.0.2:1234/?replicaSet=replName", "user", "", kSet, "replName", 2, 1, ""}, {"mongodb://[::1]:1234,[::1]:1234/dbName?foo=a&c=b&replicaSet=replName", "", "", kSet, "replName", 2, 3, "dbName"}, {"mongodb://user:pwd@[::1]/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:foobar", "user", "pwd", kMaster, "", 1, 2, ""}, {"mongodb://user:pwd@[::1]/?authMechanism=GSSAPI&gssapiServiceName=foobar", "user", "pwd", kMaster, "", 1, 2, ""}, {"mongodb:///tmp/mongodb-27017.sock", "", "", kMaster, "", 1, 0, ""}, {"mongodb:///tmp/mongodb-27017.sock,/tmp/mongodb-27018.sock/?replicaSet=replName", "", "", kSet, "replName", 2, 1, ""}}; const InvalidURITestCase invalidCases[] = { {"localhost:27017"}, {"127.0.0.2:1234,104.9.12.3:27017"}, {"127.0.0.2:1234,104.9.12.3:27017/?replName=shaun"}, {"replSetName/localhost:27027"}, {"anything,anything/?thatDoesntStartWith=mongodb://"}, {"mongodb://"}, {"mongodb://localhost:27017,localhost:27018?replicaSet=missingSlash"}, }; TEST(ConnectionString, GoodTrickyURIs) { const size_t numCases = sizeof(validCases) / sizeof(validCases[0]); for (size_t i = 0; i != numCases; ++i) { const URITestCase testCase = validCases[i]; std::cout << "Testing URI: " << testCase.URI << '\n'; std::string errMsg; const ConnectionString result = ConnectionString::parse(testCase.URI, errMsg); if (!errMsg.empty()) { std::cout << "error with uri: " << errMsg << std::endl; } ASSERT_TRUE(result.isValid()); ASSERT_TRUE(errMsg.empty()); ASSERT_EQ(testCase.uname, result.getUser()); ASSERT_EQ(testCase.password, result.getPassword()); ASSERT_EQ(testCase.type, result.type()); ASSERT_EQ(testCase.setname, result.getSetName()); ASSERT_EQ(testCase.numservers, result.getServers().size()); BSONObj options = result.getOptions(); std::set fieldNames; options.getFieldNames(fieldNames); ASSERT_EQ(testCase.numOptions, fieldNames.size()); ASSERT_EQ(testCase.database, result.getDatabase()); } } TEST(ConnectionString, InvalidURIs) { const size_t numCases = sizeof(invalidCases) / sizeof(invalidCases[0]); for (size_t i = 0; i != numCases; ++i) { const InvalidURITestCase testCase = invalidCases[i]; std::cout << "Testing URI: " << testCase.URI << '\n'; std::string errMsg; const ConnectionString result = ConnectionString::parse(testCase.URI, errMsg); ASSERT_FALSE(result.isValid()); } } // Test Deprecated URI Parsing struct DeprecatedURITestCase { std::string URI; size_t numservers; mongo::ConnectionString::ConnectionType type; std::string setname; }; const DeprecatedURITestCase validDeprecatedCases[] = { {"localhost:27017", 1, kMaster, ""}, {"localhost:27017,localhost:30000", 2, kPair, ""}, {"replName/localhost:27017,127.0.0.2:1234", 2, kSet, "replName"}, {"localhost:1050,localhost:1055/?replicaSet=rs-1234", 1, kSet, "localhost:1050,localhost:1055"}, }; const InvalidURITestCase invalidDeprecatedCases[] = { {"1.2.3.4:5555,6.7.8.9:1000,127.0.0.2:1234"}, {"localhost:27017,localhost:27018,localhost:27019,localhost:27020?replicaSet=myReplicaSet"}, }; TEST(ConnectionString, GoodDeprecatedURIs) { const size_t numCases = sizeof(validDeprecatedCases) / sizeof(validDeprecatedCases[0]); for (size_t i = 0; i != numCases; ++i) { const DeprecatedURITestCase testCase = validDeprecatedCases[i]; std::cout << "Testing URI: " << testCase.URI << '\n'; std::string errMsg; const ConnectionString result = ConnectionString::parseDeprecated(testCase.URI, errMsg); ASSERT_TRUE(result.isValid()); ASSERT_TRUE(errMsg.empty()); ASSERT_EQ(testCase.numservers, result.getServers().size()); ASSERT_EQ(testCase.type, result.type()); ASSERT_EQ(testCase.setname, result.getSetName()); } } TEST(ConnectionString, InvalidDeprecatedURIs) { const size_t numCases = sizeof(invalidDeprecatedCases) / sizeof(invalidDeprecatedCases[0]); for (size_t i = 0; i != numCases; ++i) { const InvalidURITestCase testCase = invalidDeprecatedCases[i]; std::cout << "Testing URI: " << testCase.URI << '\n'; std::string errMsg; const ConnectionString result = ConnectionString::parseDeprecated(testCase.URI, errMsg); ASSERT_FALSE(result.isValid()); } } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/client/constants.h000066400000000000000000000024711273231111400235350ustar00rootroot00000000000000// constants.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { /* query results include a 32 result flag word consisting of these bits */ enum ResultFlagType { /* returned, with zero results, when getMore is called but the cursor id is not valid at the server. */ ResultFlag_CursorNotFound = 1, /* { $err : ... } is being returned */ ResultFlag_ErrSet = 2, /* Have to update config from the server, usually $err is also set */ ResultFlag_ShardConfigStale = 4, /* for backward compatibility: this let's us know the server supports the QueryOption_AwaitData option. if it doesn't, a repl slave client should sleep a little between getMore's. */ ResultFlag_AwaitCapable = 8 }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/cyrus_sasl_client_session.cpp000066400000000000000000000225161273231111400273460ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/cyrus_sasl_client_session.h" #include #include "mongo/base/init.h" #include "mongo/client/native_sasl_client_session.h" #include "mongo/util/assert_util.h" #include "mongo/util/mongoutils/str.h" namespace mongo { namespace { SaslClientSession* createCyrusSaslClientSession(const std::string& mech) { if (mech == "SCRAM-SHA-1") { return new NativeSaslClientSession(); } return new CyrusSaslClientSession(); } typedef int (*SaslCallbackFn)(); /* * Mutex functions to be used by the SASL library, if the client doesn't initialize the library * for us. */ void* saslMutexAlloc(void) { return new boost::mutex; } int saslMutexLock(void* mutex) { static_cast(mutex)->lock(); return SASL_OK; } int saslMutexUnlock(void* mutex) { static_cast(mutex)->unlock(); return SASL_OK; } void saslMutexFree(void* mutex) { delete static_cast(mutex); } /** * Configures the SASL library to use allocator and mutex functions we specify, * unless the client application has previously initialized the SASL library. */ MONGO_INITIALIZER(CyrusSaslAllocatorsAndMutexes)(InitializerContext*) { sasl_set_mutex(saslMutexAlloc, saslMutexLock, saslMutexUnlock, saslMutexFree); return Status::OK(); } int saslClientLogSwallow(void* context, int priority, const char* message) { return SASL_OK; // do nothing } /** * Initializes the client half of the SASL library, but is effectively a no-op if the client * application has already done it. * * If a client wishes to override this initialization but keep the allocator and mutex * initialization, it should implement a MONGO_INITIALIZER_GENERAL with * CyrusSaslAllocatorsAndMutexes as a prerequisite and CyrusSaslClientContext as a * dependent. If it wishes to override both, it should implement a MONGO_INITIALIZER_GENERAL * with CyrusSaslAllocatorsAndMutexes and CyrusSaslClientContext as dependents, or * initialize the library before calling mongo::runGlobalInitializersOrDie(). */ MONGO_INITIALIZER_WITH_PREREQUISITES(CyrusSaslClientContext, ("NativeSaslClientContext", "CyrusSaslAllocatorsAndMutexes")) (InitializerContext* context) { static sasl_callback_t saslClientGlobalCallbacks[] = { {SASL_CB_LOG, SaslCallbackFn(saslClientLogSwallow), NULL /* context */}, {SASL_CB_LIST_END}}; // If the client application has previously called sasl_client_init(), the callbacks passed // in here are ignored. // // TODO: Call sasl_client_done() at shutdown when we have a story for orderly shutdown. int result = sasl_client_init(saslClientGlobalCallbacks); if (result != SASL_OK) { return Status(ErrorCodes::UnknownError, mongoutils::str::stream() << "Could not initialize sasl client components (" << sasl_errstring(result, NULL, NULL) << ")"); } SaslClientSession::create = createCyrusSaslClientSession; return Status::OK(); } /** * Callback registered on the sasl_conn_t underlying a CyrusSaslClientSession to allow the Cyrus * SASL library to query for the authentication id and other simple string configuration parameters. * * Note that in Mongo, the authentication and authorization ids (authid and authzid) are always * the same. These correspond to SASL_CB_AUTHNAME and SASL_CB_USER. */ int saslClientGetSimple(void* context, int id, const char** result, unsigned* resultLen) throw() { CyrusSaslClientSession* session = static_cast(context); if (!session || !result) return SASL_BADPARAM; CyrusSaslClientSession::Parameter requiredParameterId; switch (id) { case SASL_CB_AUTHNAME: case SASL_CB_USER: requiredParameterId = CyrusSaslClientSession::parameterUser; break; default: return SASL_FAIL; } if (!session->hasParameter(requiredParameterId)) return SASL_FAIL; StringData value = session->getParameter(requiredParameterId); *result = value.rawData(); if (resultLen) *resultLen = static_cast(value.size()); return SASL_OK; } /** * Callback registered on the sasl_conn_t underlying a CyrusSaslClientSession to allow * the Cyrus SASL library to query for the password data. */ int saslClientGetPassword(sasl_conn_t* conn, void* context, int id, sasl_secret_t** outSecret) throw() { CyrusSaslClientSession* session = static_cast(context); if (!session || !outSecret) return SASL_BADPARAM; sasl_secret_t* secret = session->getPasswordAsSecret(); if (secret == NULL) { sasl_seterror(conn, 0, "No password data provided"); return SASL_FAIL; } *outSecret = secret; return SASL_OK; } } // namespace CyrusSaslClientSession::CyrusSaslClientSession() : SaslClientSession(), _saslConnection(NULL), _step(0), _done(false) { const sasl_callback_t callbackTemplate[maxCallbacks] = { {SASL_CB_AUTHNAME, SaslCallbackFn(saslClientGetSimple), this}, {SASL_CB_USER, SaslCallbackFn(saslClientGetSimple), this}, {SASL_CB_PASS, SaslCallbackFn(saslClientGetPassword), this}, {SASL_CB_LIST_END}}; std::copy(callbackTemplate, callbackTemplate + maxCallbacks, _callbacks); } CyrusSaslClientSession::~CyrusSaslClientSession() { sasl_dispose(&_saslConnection); } void CyrusSaslClientSession::setParameter(Parameter id, const StringData& value) { fassert(18665, id >= 0 && id < numParameters); if (id == parameterPassword) { // The parameterPassword is stored as a sasl_secret_t, while other // parameters are stored directly. This facilitates memory ownership management for // getPasswordAsSecret(). _secret.reset(new char[sizeof(sasl_secret_t) + value.size() + 1]); sasl_secret_t* secret = static_cast(static_cast(_secret.get())); secret->len = value.size(); value.copyTo(static_cast(static_cast(&secret->data[0])), false); } SaslClientSession::setParameter(id, value); } sasl_secret_t* CyrusSaslClientSession::getPasswordAsSecret() { // See comment in setParameter() about the special storage of parameterPassword. return static_cast(static_cast(_secret.get())); } Status CyrusSaslClientSession::initialize() { if (_saslConnection != NULL) return Status(ErrorCodes::AlreadyInitialized, "Cannot reinitialize CyrusSaslClientSession."); int result = sasl_client_new(getParameter(parameterServiceName).toString().c_str(), getParameter(parameterServiceHostname).toString().c_str(), NULL, NULL, _callbacks, 0, &_saslConnection); if (SASL_OK != result) { return Status(ErrorCodes::UnknownError, mongoutils::str::stream() << sasl_errstring(result, NULL, NULL)); } return Status::OK(); } Status CyrusSaslClientSession::step(const StringData& inputData, std::string* outputData) { const char* output = NULL; unsigned outputSize = 0xFFFFFFFF; int result; if (_step == 0) { const char* actualMechanism; result = sasl_client_start(_saslConnection, getParameter(parameterMechanism).toString().c_str(), NULL, &output, &outputSize, &actualMechanism); } else { result = sasl_client_step(_saslConnection, inputData.rawData(), static_cast(inputData.size()), NULL, &output, &outputSize); } ++_step; switch (result) { case SASL_OK: _done = true; // Fall through case SASL_CONTINUE: *outputData = std::string(output, outputSize); return Status::OK(); case SASL_NOMECH: return Status(ErrorCodes::BadValue, sasl_errdetail(_saslConnection)); case SASL_BADAUTH: return Status(ErrorCodes::AuthenticationFailed, sasl_errdetail(_saslConnection)); default: return Status(ErrorCodes::ProtocolError, sasl_errdetail(_saslConnection)); } } } // namespace MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(client_cyrus_sasl_client_session) mongo-cxx-driver-legacy-1.1.2/src/mongo/client/cyrus_sasl_client_session.h000066400000000000000000000044711273231111400270130ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/sasl_client_session.h" #include namespace mongo { /** * Implementation of the client side of a SASL authentication conversation. * using the Cyrus SASL library. */ class CyrusSaslClientSession : public SaslClientSession { MONGO_DISALLOW_COPYING(CyrusSaslClientSession); public: CyrusSaslClientSession(); ~CyrusSaslClientSession(); /** * Overriding to store the password data in sasl_secret_t format */ virtual void setParameter(Parameter id, const StringData& value); /** * Returns the value of the parameterPassword parameter in the form of a sasl_secret_t, used * by the Cyrus SASL library's SASL_CB_PASS callback. The session object owns the storage * referenced by the returned sasl_secret_t*, which will remain in scope according to the * same rules as given for SaslClientSession::getParameter(). */ sasl_secret_t* getPasswordAsSecret(); virtual Status initialize(); virtual Status step(const StringData& inputData, std::string* outputData); virtual bool isDone() const { return _done; } private: /// Maximum number of Cyrus SASL callbacks stored in _callbacks. static const int maxCallbacks = 4; /// Underlying Cyrus SASL library connection object. sasl_conn_t* _saslConnection; // Number of successfully completed conversation steps. int _step; /// See isDone(). bool _done; /// Stored of password in sasl_secret_t format boost::scoped_array _secret; /// Callbacks registered on _saslConnection for providing the Cyrus SASL library with /// parameter values, etc. sasl_callback_t _callbacks[maxCallbacks]; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient.cpp000066400000000000000000002514421273231111400236440ustar00rootroot00000000000000// dbclient.cpp - connect to a Mongo database as a database, from C++ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/base/init.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/bson/util/builder.h" #include "mongo/client/constants.h" #include "mongo/client/command_writer.h" #include "mongo/client/dbclient_rs.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientcursorshim.h" #include "mongo/client/dbclientcursorshimarray.h" #include "mongo/client/dbclientcursorshimcursorid.h" #include "mongo/client/dbclientcursorshimtransform.h" #include "mongo/client/dbclient_writer.h" #include "mongo/client/insert_write_operation.h" #include "mongo/client/options.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/client/update_write_operation.h" #include "mongo/client/delete_write_operation.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/client/wire_protocol_writer.h" #include "mongo/client/write_result.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/namespace_string.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/password_digest.h" #include #include #include #include #include #include #include #ifdef MONGO_SSL #include "mongo/client/native_sasl_client_session.h" #endif namespace mongo { using std::auto_ptr; using std::endl; using std::list; using std::map; using std::string; using std::stringstream; using std::vector; AtomicInt64 DBClientBase::ConnectionIdSequence; const char* const saslCommandUserSourceFieldName = "userSource"; const char kBypassDocumentValidationKey[] = "bypassDocumentValidation"; const int defaultMaxBsonObjectSize = 16 * 1024 * 1024; const int defaultMaxMessageSizeBytes = defaultMaxBsonObjectSize * 2; const int defaultMaxWriteBatchSize = 1000; namespace { const char kMongoDBURL[] = // scheme: non-capturing "mongodb://" // credentials: two inner captures for user and password "(?:([^:]+)(?::([^@]+))?@)?" // servers: grabs all host:port or UNIX socket names "((?:(?:[^\\/]+|/.+.sock?),?)+)" // database: matches anything but the chars that cannot // be part of a MongoDB database name. "(?:/([^/\\.\\ \"*<>:\\|\\?]*))?" // options "(?:\\?(?:(.+=.+)&?)+)*"; } // namespace void ConnectionString::_fillServers(string s, bool legacy) { // // Custom-handled servers/replica sets start with '$' // According to RFC-1123/952, this will not overlap with valid hostnames // (also disallows $replicaSetName hosts) // if (s.find('$') == 0) _type = CUSTOM; if (legacy) { string::size_type idx = s.find('/'); if (idx != string::npos && idx != 0) { _setName = s.substr(0, idx); s = s.substr(idx + 1); if (_type != CUSTOM) _type = SET; } } string::size_type idx; while ((idx = s.find(',')) != string::npos) { _servers.push_back(HostAndPort(s.substr(0, idx))); s = s.substr(idx + 1); } _servers.push_back(HostAndPort(s)); } void ConnectionString::_finishInit() { // Needed here as well b/c the parsing logic isn't used in all constructors // TODO: Refactor so that the parsing logic *is* used in all constructors if (_type == MASTER && _servers.size() > 0) { if (_servers[0].host().find('$') == 0) { _type = CUSTOM; } } stringstream ss; if (_type == SET) ss << _setName << "/"; for (unsigned i = 0; i < _servers.size(); i++) { if (i > 0) ss << ","; ss << _servers[i].toString(); } _string = ss.str(); } namespace { const char kAuthMechanismPropertiesKey[] = "mechanism_properties"; // CANONICALIZE_HOST_NAME is currently unsupported const char kAuthServiceName[] = "SERVICE_NAME"; const char kAuthServiceRealm[] = "SERVICE_REALM"; const char kAuthMechMongoCR[] = "MONGODB-CR"; const char kAuthMechScramSha1[] = "SCRAM-SHA-1"; const char kAuthMechDefault[] = "DEFAULT"; const char* const kSupportedAuthMechanismProperties[] = {kAuthServiceName, kAuthServiceRealm}; // bootleg std::end for c-style arrays. template T* endOf(T(&arr)[N]) { return arr + N; } BSONObj parseAuthMechanismProperties(const std::string& propStr) { BSONObjBuilder bob; std::vector props; boost::algorithm::split(props, propStr, boost::algorithm::is_any_of(",:")); for (std::vector::const_iterator it = props.begin(); it != props.end(); ++it) { std::string prop((boost::algorithm::to_upper_copy(*it))); // normalize case uassert(ErrorCodes::FailedToParse, str::stream() << "authMechanismProperty: " << *it << " is not supported", std::count(kSupportedAuthMechanismProperties, endOf(kSupportedAuthMechanismProperties), prop)); ++it; uassert(ErrorCodes::FailedToParse, str::stream() << "authMechanismProperty: " << prop << " must have a value", it != props.end()); bob.append(prop, *it); } return bob.obj(); } string authKeyCopyDBMongoCR(const string& username, const string& password, const string& nonce) { md5digest d; string passwordDigest = createPasswordDigest(username, password); { md5_state_t st; md5_init(&st); md5_append(&st, reinterpret_cast(nonce.c_str()), nonce.size()); md5_append(&st, reinterpret_cast(username.data()), username.length()); md5_append(&st, reinterpret_cast(passwordDigest.c_str()), passwordDigest.size()); md5_finish(&st, d); } return digestToString(d); } } // namespace BSONObj ConnectionString::_makeAuthObjFromOptions(int maxWireVersion) const { BSONObjBuilder bob; // Add the username and optional password invariant(!_user.empty()); std::string username(_user); // may have to tack on service realm before we append if (!_password.empty()) bob.append(saslCommandPasswordFieldName, _password); BSONElement elt = _options.getField("authSource"); if (!elt.eoo()) { bob.appendAs(elt, saslCommandUserDBFieldName); } else if (!_database.empty()) { bob.append(saslCommandUserDBFieldName, _database); } else { bob.append(saslCommandUserDBFieldName, "admin"); } elt = _options.getField("authMechanism"); if (!elt.eoo()) { bob.appendAs(elt, saslCommandMechanismFieldName); } else if (maxWireVersion >= 3) { bob.append(saslCommandMechanismFieldName, kAuthMechScramSha1); } else { bob.append(saslCommandMechanismFieldName, kAuthMechMongoCR); } elt = _options.getField("authMechanismProperties"); if (!elt.eoo()) { BSONObj parsed(parseAuthMechanismProperties(elt.String())); bool hasNameProp = parsed.hasField(kAuthServiceName); bool hasRealmProp = parsed.hasField(kAuthServiceRealm); uassert(ErrorCodes::FailedToParse, "Cannot specify both gssapiServiceName and SERVICE_NAME", !(hasNameProp && _options.hasField("gssapiServiceName"))); // we append the parsed object so that mechanisms that don't accept it can assert. bob.append(kAuthMechanismPropertiesKey, parsed); // we still append using the old way the SASL code expects it if (hasNameProp) { bob.append(saslCommandServiceNameFieldName, parsed[kAuthServiceName].String()); } // if we specified a realm, we just append it to the username as the SASL code // expects it that way. if (hasRealmProp) { username.append("@").append(parsed[kAuthServiceRealm].String()); } } elt = _options.getField("gssapiServiceName"); if (!elt.eoo()) bob.appendAs(elt, saslCommandServiceNameFieldName); bob.append("user", username); return bob.obj(); } boost::mutex ConnectionString::_connectHookMutex; ConnectionString::ConnectionHook* ConnectionString::_connectHook = NULL; DBClientBase* ConnectionString::connect(string& errmsg, double socketTimeout) const { switch (_type) { case MASTER: { auto_ptr c(new DBClientConnection(true)); c->setSoTimeout(socketTimeout); LOG(1) << "creating new connection to:" << _servers[0] << endl; if (!c->connect(_servers[0], errmsg)) { return 0; } if (!_user.empty()) { c->auth(_makeAuthObjFromOptions(c->getMaxWireVersion())); } LOG(1) << "connected connection!" << endl; return c.release(); } case PAIR: case SET: { auto_ptr set( new DBClientReplicaSet(_setName, _servers, socketTimeout)); if (!set->connect()) { errmsg = "connect failed to replica set "; errmsg += toString(); return 0; } if (!_user.empty()) { set->auth(_makeAuthObjFromOptions(set->getMaxWireVersion())); } return set.release(); } case CUSTOM: { // Lock in case other things are modifying this at the same time boost::lock_guard lk(_connectHookMutex); // Allow the replacement of connections with other connections - useful for testing. uassert(16335, "custom connection to " + this->toString() + " specified with no connection hook", _connectHook); // Double-checked lock, since this will never be active during normal operation DBClientBase* replacementConn = _connectHook->connect(*this, errmsg, socketTimeout); log() << "replacing connection to " << this->toString() << " with " << (replacementConn ? replacementConn->getServerAddress() : "(empty)") << endl; return replacementConn; } case INVALID: throw UserException(13421, "trying to connect to invalid ConnectionString"); break; } verify(0); return 0; } bool ConnectionString::sameLogicalEndpoint(const ConnectionString& other) const { if (_type != other._type) return false; switch (_type) { case INVALID: return true; case MASTER: return _servers[0] == other._servers[0]; case PAIR: if (_servers[0] == other._servers[0]) return _servers[1] == other._servers[1]; return (_servers[0] == other._servers[1]) && (_servers[1] == other._servers[0]); case SET: return _setName == other._setName; case CUSTOM: return _string == other._string; } verify(false); } ConnectionString ConnectionString::parse(const string& url, string& errmsg) { if (boost::algorithm::starts_with(url, "mongodb://")) return _parseURL(url, errmsg); errmsg = string("invalid connection string [") + url + "]"; return ConnectionString(); // INVALID } ConnectionString ConnectionString::parseDeprecated(const string& address, string& errmsg) { string::size_type i = address.find('/'); if (i != string::npos && i != 0) { // replica set return ConnectionString(SET, address.substr(i + 1), address.substr(0, i)); } int numCommas = str::count(address, ','); if (numCommas == 0) return ConnectionString(HostAndPort(address)); if (numCommas == 1) return ConnectionString(PAIR, address); errmsg = string("invalid connection string [") + address + "]"; return ConnectionString(); // INVALID } ConnectionString ConnectionString::_parseURL(const string& url, string& errmsg) { const boost::regex mongoUrlRe(kMongoDBURL); boost::smatch matches; if (!boost::regex_match(url, matches, mongoUrlRe)) { errmsg = "Failed to parse mongodb:// URL: " + url; return ConnectionString(); } // We have 5 top level captures, plus the whole input. invariant(matches.size() == 6); if (!matches[3].matched) { errmsg = "No server(s) specified"; return ConnectionString(); } std::map options; if (matches[5].matched) { const std::string optionsMatch = matches[5].str(); std::vector > optionsTokens; boost::algorithm::split(optionsTokens, optionsMatch, boost::algorithm::is_any_of("=&")); if (optionsTokens.size() % 2 != 0) { errmsg = "Missing a key or value in the options for mongodb:// URL: " + url; return ConnectionString(); } for (size_t i = 0; i != optionsTokens.size(); i = i + 2) options[std::string(optionsTokens[i].begin(), optionsTokens[i].end())] = std::string(optionsTokens[i + 1].begin(), optionsTokens[i + 1].end()); } // Validate options against global driver state, and transform // or append relevant options to the auth struct. std::map::const_iterator optIter; // If a replica set option was specified, store it in the 'setName' field. bool haveSetName; std::string setName; if ((haveSetName = ((optIter = options.find("replicaSet")) != options.end()))) setName = optIter->second; // If an SSL option was specified that conflicts with the global setting, error out. // The driver doesn't offer per connection settings. if ((optIter = options.find("ssl")) != options.end()) { if (optIter->second != (client::Options::current().SSLEnabled() ? "true" : "false")) { errmsg = "Cannot override global driver SSL state in connection URL"; return ConnectionString(); } } // Add all remaining options into the bson object BSONObjBuilder optionsBob; for (optIter = options.begin(); optIter != options.end(); ++optIter) optionsBob.append(optIter->first, optIter->second); std::string servers = matches[3].str(); const bool direct = !haveSetName && (servers.find(',') == std::string::npos); if (!direct && setName.empty()) { errmsg = "Cannot list multiple servers in URL without 'replicaSet' option"; return ConnectionString(); } return ConnectionString(direct ? MASTER : SET, matches[1].str(), matches[2].str(), servers, matches[4].str(), setName, optionsBob.obj()); } string ConnectionString::typeToString(ConnectionType type) { switch (type) { case INVALID: return "invalid"; case MASTER: return "master"; case PAIR: return "pair"; case SET: return "set"; case CUSTOM: return "custom"; } verify(0); return ""; } const BSONField Query::ReadPrefField("$readPreference"); const BSONField Query::ReadPrefModeField("mode"); const BSONField Query::ReadPrefTagsField("tags"); static const char* maxTimeMsField = "$maxTimeMS"; Query::Query(const string& json) : obj(fromjson(json)) {} Query::Query(const char* json) : obj(fromjson(json)) {} Query& Query::hint(const string& indexName) { appendComplex("$hint", indexName); return *this; } Query& Query::where(const string& jscode, BSONObj scope) { /* use where() before sort() and hint() and explain(), else this will assert. */ verify(!isComplex()); BSONObjBuilder b; b.appendElements(obj); b.appendWhere(jscode, scope); obj = b.obj(); return *this; } void Query::makeComplex() { if (isComplex()) return; BSONObjBuilder b; b.append("query", obj); obj = b.obj(); } Query& Query::sort(const BSONObj& s) { appendComplex("orderby", s); return *this; } Query& Query::hint(BSONObj keyPattern) { appendComplex("$hint", keyPattern); return *this; } Query& Query::maxTimeMs(int millis) { appendComplex(maxTimeMsField, millis); return *this; } Query& Query::explain() { appendComplex("$explain", true); return *this; } Query& Query::snapshot() { appendComplex("$snapshot", true); return *this; } Query& Query::minKey(const BSONObj& val) { appendComplex("$min", val); return *this; } Query& Query::maxKey(const BSONObj& val) { appendComplex("$max", val); return *this; } bool Query::isComplex(const BSONObj& obj, bool* hasDollar) { if (obj.hasElement("query")) { if (hasDollar) *hasDollar = false; return true; } if (obj.hasElement("$query")) { if (hasDollar) *hasDollar = true; return true; } return false; } BSONObj Query::getModifiers() const { std::set names; obj.getFieldNames(names); BSONObjBuilder complexFields; std::set::const_iterator nameIterator; for (nameIterator = names.begin(); nameIterator != names.end(); ++nameIterator) { if (nameIterator->find('$') == 0) complexFields.append(obj.getField(*nameIterator)); } return complexFields.obj(); } Query& Query::readPref(ReadPreference pref, const BSONArray& tags) { string mode; switch (pref) { case ReadPreference_PrimaryOnly: mode = "primary"; break; case ReadPreference_PrimaryPreferred: mode = "primaryPreferred"; break; case ReadPreference_SecondaryOnly: mode = "secondary"; break; case ReadPreference_SecondaryPreferred: mode = "secondaryPreferred"; break; case ReadPreference_Nearest: mode = "nearest"; break; } BSONObjBuilder readPrefDocBuilder; readPrefDocBuilder << ReadPrefModeField(mode); if (!tags.isEmpty()) { readPrefDocBuilder << ReadPrefTagsField(tags); } appendComplex(ReadPrefField.name().c_str(), readPrefDocBuilder.done()); return *this; } bool Query::isComplex(bool* hasDollar) const { return isComplex(obj, hasDollar); } bool Query::hasReadPreference(const BSONObj& queryObj) { const bool hasReadPrefOption = queryObj["$queryOptions"].isABSONObj() && queryObj["$queryOptions"].Obj().hasField(ReadPrefField.name()); return (Query::isComplex(queryObj) && queryObj.hasField(ReadPrefField.name())) || hasReadPrefOption; } bool Query::hasReadPreference() const { return hasReadPreference(obj); } bool Query::hasHint() const { return obj.hasField("$hint"); } bool Query::hasMaxTimeMs() const { return obj.hasField(maxTimeMsField); } BSONObj Query::getFilter() const { bool hasDollar; if (!isComplex(&hasDollar)) return obj; return obj.getObjectField(hasDollar ? "$query" : "query"); } BSONObj Query::getSort() const { if (!isComplex()) return BSONObj(); BSONObj ret = obj.getObjectField("orderby"); if (ret.isEmpty()) ret = obj.getObjectField("$orderby"); return ret; } BSONElement Query::getHint() const { if (!isComplex()) return BSONElement(); return obj.getField("$hint"); } BSONObj Query::getReadPref() const { return obj.getObjectField(ReadPrefField.name()); } int Query::getMaxTimeMs() const { return obj.getIntField(maxTimeMsField); } bool Query::isExplain() const { return isComplex() && obj.getBoolField("$explain"); } string Query::toString() const { return obj.toString(); } /* --- dbclientcommands --- */ bool DBClientWithCommands::isOk(const BSONObj& o) { return o["ok"].trueValue(); } bool DBClientWithCommands::isNotMasterErrorString(const BSONElement& e) { return e.type() == String && str::contains(e.valuestr(), "not master"); } enum QueryOptions DBClientWithCommands::availableOptions() { if (!_haveCachedAvailableOptions) { _cachedAvailableOptions = _lookupAvailableOptions(); _haveCachedAvailableOptions = true; } return _cachedAvailableOptions; } enum QueryOptions DBClientWithCommands::_lookupAvailableOptions() { BSONObj ret; if (runCommand("admin", BSON("availablequeryoptions" << 1), ret)) { return QueryOptions(ret.getIntField("options")); } return QueryOptions(0); } void DBClientWithCommands::setRunCommandHook(RunCommandHookFunc func) { _runCommandHook = func; } void DBClientWithCommands::setPostRunCommandHook(PostRunCommandHookFunc func) { _postRunCommandHook = func; } bool DBClientWithCommands::runCommand(const string& dbname, const BSONObj& cmd, BSONObj& info, int options) { string ns = dbname + ".$cmd"; if (_runCommandHook) { BSONObjBuilder cmdObj; cmdObj.appendElements(cmd); _runCommandHook(&cmdObj); info = findOne(ns, cmdObj.done(), 0, options); } else { info = findOne(ns, cmd, 0, options); } if (_postRunCommandHook) { _postRunCommandHook(info, getServerAddress()); } return isOk(info); } /* note - we build a bson obj here -- for something that is super common like getlasterror you should have that object prebuilt as that would be faster. */ bool DBClientWithCommands::simpleCommand(const string& dbname, BSONObj* info, const string& command) { BSONObj o; if (info == 0) info = &o; BSONObjBuilder b; b.append(command, 1); return runCommand(dbname, b.done(), *info); } unsigned long long DBClientWithCommands::count( const string& myns, const Query& query, int options, int limit, int skip) { BSONObj cmd = _countCmd(myns, query, options, limit, skip); BSONObj res; if (!runCommand(nsToDatabase(myns), cmd, res, options)) uasserted(11010, string("count fails:") + res.toString()); return res["n"].numberLong(); } BSONObj DBClientWithCommands::_countCmd( const string& myns, const Query& query, int options, int limit, int skip) { NamespaceString ns(myns); BSONObjBuilder b; b.append("count", ns.coll()); b.append("query", query.getFilter()); if (limit) b.append("limit", limit); if (skip) b.append("skip", skip); if (query.isComplex()) { if (query.hasHint()) { BSONElement hint(query.getHint()); if (hint.isABSONObj()) b.append("hint", hint.Obj()); else b.append("hint", hint.String()); } // We don't want $hint anymore as we've already used it inside the command b.appendElements(query.getModifiers().removeField("$hint")); } return b.obj(); } BSONObj DBClientWithCommands::getLastErrorDetailed(bool fsync, bool j, int w, int wtimeout) { return getLastErrorDetailed("admin", fsync, j, w, wtimeout); } BSONObj DBClientWithCommands::getLastErrorDetailed( const std::string& db, bool fsync, bool j, int w, int wtimeout) { BSONObj info; BSONObjBuilder b; b.append("getlasterror", 1); if (fsync) b.append("fsync", 1); if (j) b.append("j", 1); // only affects request when greater than one node if (w >= 1) b.append("w", w); else if (w == -1) b.append("w", "majority"); if (wtimeout > 0) b.append("wtimeout", wtimeout); runCommand(db, b.obj(), info); return info; } string DBClientWithCommands::getLastError(bool fsync, bool j, int w, int wtimeout) { return getLastError("admin", fsync, j, w, wtimeout); } string DBClientWithCommands::getLastError( const std::string& db, bool fsync, bool j, int w, int wtimeout) { BSONObj info = getLastErrorDetailed(db, fsync, j, w, wtimeout); return getLastErrorString(info); } string DBClientWithCommands::getLastErrorString(const BSONObj& info) { if (info["ok"].trueValue()) { BSONElement e = info["err"]; if (e.eoo()) return ""; if (e.type() == Object) return e.toString(); return e.str(); } else { // command failure BSONElement e = info["errmsg"]; if (e.eoo()) return ""; if (e.type() == Object) return "getLastError command failed: " + e.toString(); return "getLastError command failed: " + e.str(); } } const BSONObj getpreverrorcmdobj = fromjson("{getpreverror:1}"); BSONObj DBClientWithCommands::getPrevError() { BSONObj info; runCommand("admin", getpreverrorcmdobj, info); return info; } BSONObj getnoncecmdobj = fromjson("{getnonce:1}"); string DBClientWithCommands::createPasswordDigest(const string& username, const string& clearTextPassword) { return mongo::createPasswordDigest(username, clearTextPassword); } void DBClientWithCommands::_auth(const BSONObj& params) { std::string mechanism; uassertStatusOK(bsonExtractStringField(params, saslCommandMechanismFieldName, &mechanism)); uassert(17232, "You cannot specify both 'db' and 'userSource'. Please use only 'db'.", !(params.hasField(saslCommandUserDBFieldName) && params.hasField(saslCommandUserSourceFieldName))); if (mechanism == kAuthMechMongoCR) { std::string db; if (params.hasField(saslCommandUserSourceFieldName)) { uassertStatusOK(bsonExtractStringField(params, saslCommandUserSourceFieldName, &db)); } else { uassertStatusOK(bsonExtractStringField(params, saslCommandUserDBFieldName, &db)); } std::string user; uassertStatusOK(bsonExtractStringField(params, saslCommandUserFieldName, &user)); std::string password; uassertStatusOK(bsonExtractStringField(params, saslCommandPasswordFieldName, &password)); bool digestPassword; uassertStatusOK(bsonExtractBooleanFieldWithDefault( params, saslCommandDigestPasswordFieldName, true, &digestPassword)); uassert(ErrorCodes::AuthenticationFailed, "Cannot set mechanism_properties when using MONGODB_CR", !params.hasField(kAuthMechanismPropertiesKey)); BSONObj result; uassert(result["code"].Int(), result.toString(), _authMongoCR(db, user, password, &result, digestPassword)); } #ifdef MONGO_SSL else if (mechanism == StringData("MONGODB-X509", StringData::LiteralTag())) { std::string db; if (params.hasField(saslCommandUserSourceFieldName)) { uassertStatusOK(bsonExtractStringField(params, saslCommandUserSourceFieldName, &db)); } else { uassertStatusOK(bsonExtractStringField(params, saslCommandUserDBFieldName, &db)); } std::string user; uassertStatusOK(bsonExtractStringField(params, saslCommandUserFieldName, &user)); uassert(ErrorCodes::AuthenticationFailed, "Please enable SSL on the client-side to use the MONGODB-X509 " "authentication mechanism.", getSSLManager() != NULL); uassert(ErrorCodes::AuthenticationFailed, "Username \"" + user + "\" does not match the provided client certificate user \"" + getSSLManager()->getClientSubjectName() + "\"", user == getSSLManager()->getClientSubjectName()); uassert(ErrorCodes::AuthenticationFailed, "Cannot set mechanism_properties when using MONGODB_X509", !params.hasField(kAuthMechanismPropertiesKey)); BSONObj result; uassert(result["code"].Int(), result.toString(), _authX509(db, user, &result)); } #endif else if (saslClientAuthenticate != NULL) { uassertStatusOK(saslClientAuthenticate(this, params)); } else { std::string error = mechanism + " mechanism support not compiled into client library." " (Some mechanisms require the driver be compiled" " with the flags --ssl or --use-sasl-client)"; uasserted(ErrorCodes::BadValue, error); } }; void DBClientWithCommands::auth(const BSONObj& params) { _auth(params); } bool DBClientWithCommands::auth(const string& dbname, const string& username, const string& password_text, string& errmsg, bool digestPassword) { try { const char* mech = kAuthMechMongoCR; if (_maxWireVersion >= 3) { mech = kAuthMechScramSha1; } _auth(BSON(saslCommandMechanismFieldName << mech << saslCommandUserDBFieldName << dbname << saslCommandUserFieldName << username << saslCommandPasswordFieldName << password_text << saslCommandDigestPasswordFieldName << digestPassword)); return true; } catch (const UserException& ex) { if (ex.getCode() != ErrorCodes::AuthenticationFailed) throw; errmsg = ex.what(); return false; } } bool DBClientWithCommands::_authMongoCR(const string& dbname, const string& username, const string& password_text, BSONObj* info, bool digestPassword) { string password = password_text; if (digestPassword) password = createPasswordDigest(username, password_text); string nonce; if (!runCommand(dbname, getnoncecmdobj, *info)) { return false; } { BSONElement e = info->getField("nonce"); verify(e.type() == String); nonce = e.valuestr(); } BSONObj authCmd; BSONObjBuilder b; { b << "authenticate" << 1 << "nonce" << nonce << "user" << username; md5digest d; { md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t*)nonce.c_str(), nonce.size()); md5_append(&st, (const md5_byte_t*)username.data(), username.length()); md5_append(&st, (const md5_byte_t*)password.c_str(), password.size()); md5_finish(&st, d); } b << "key" << digestToString(d); authCmd = b.done(); } if (runCommand(dbname, authCmd, *info)) { return true; } return false; } bool DBClientWithCommands::_authX509(const string& dbname, const string& username, BSONObj* info) { BSONObj authCmd; BSONObjBuilder cmdBuilder; cmdBuilder << "authenticate" << 1 << "mechanism" << "MONGODB-X509" << "user" << username; authCmd = cmdBuilder.done(); if (runCommand(dbname, authCmd, *info)) { return true; } return false; } void DBClientWithCommands::logout(const string& dbname, BSONObj& info) { runCommand(dbname, BSON("logout" << 1), info); } BSONObj ismastercmdobj = fromjson("{\"ismaster\":1}"); bool DBClientWithCommands::isMaster(bool& isMaster, BSONObj* info) { BSONObj o; if (info == 0) info = &o; bool ok = runCommand("admin", ismastercmdobj, *info); isMaster = info->getField("ismaster").trueValue(); return ok; } bool DBClientWithCommands::createCollection( const string& ns, long long size, bool capped, int max, BSONObj* info) { return createCollectionWithOptions(ns, size, capped, max, BSONObj(), info); } bool DBClientWithCommands::createCollectionWithOptions( const string& ns, long long size, bool capped, int max, const BSONObj& extra, BSONObj* info) { verify(!capped || size); BSONObj o; if (info == 0) info = &o; BSONObjBuilder b; string db = nsToDatabase(ns); b.append("create", ns.c_str() + db.length() + 1); if (size) b.append("size", size); if (capped) b.append("capped", true); if (max) b.append("max", max); if (!extra.isEmpty()) b.appendElements(extra); return runCommand(db.c_str(), b.done(), *info); } bool DBClientWithCommands::copyDatabase(const string& fromdb, const string& todb, const string& fromhost, const string& mechanism, const string& username, const string& password, BSONObj* info) { BSONObj o; if (info == 0) info = &o; BSONObjBuilder copydbCmd; copydbCmd.append("copydb", 1); copydbCmd.append("fromhost", fromhost); copydbCmd.append("fromdb", fromdb); copydbCmd.append("todb", todb); // If we don't have a username, or if we're copying locally, // just run the command without authenticating if (username == "" || fromhost == "") { return runCommand("admin", copydbCmd.done(), *info); } // Otherwise, take or guess the auth mechanism string authMech; if (mechanism != kAuthMechDefault) { uassert(0, "auth mechanism must be MONGODB-CR or SCRAM-SHA-1", (mechanism == kAuthMechMongoCR || mechanism == kAuthMechScramSha1)); authMech = mechanism; } #ifdef MONGO_SSL else if ((static_cast(this))->getMaxWireVersion() >= 3) { authMech = kAuthMechScramSha1; } #endif else { authMech = kAuthMechMongoCR; } if (authMech == kAuthMechMongoCR) { // run MONGODB-CR copydb BSONObj nonceInfo; BSONObjBuilder nonceCmd; BSONElement e; string nonce; nonceCmd.append("copydbgetnonce", 1); nonceCmd.append("fromhost", fromhost); verify(runCommand("admin", nonceCmd.done(), nonceInfo)); { BSONElement e = nonceInfo.getField("nonce"); verify(e.type() == String); nonce = e.valuestr(); } copydbCmd.append("username", username); copydbCmd.append("nonce", nonce); copydbCmd.append("key", authKeyCopyDBMongoCR(username, password, nonce)); return runCommand("admin", copydbCmd.done(), *info); } else { // run SCRAM-SHA-1 copydb, but only with SSL #ifndef MONGO_SSL uassert(0, "SCRAM-SHA-1 authentication requires driver to be built with SSL", false); #endif #ifdef MONGO_SSL string hashedPwd = createPasswordDigest(username, password); // create and initialize our sasl session boost::scoped_ptr session(new NativeSaslClientSession()); session->setParameter(SaslClientSession::parameterMechanism, kAuthMechScramSha1); session->setParameter(SaslClientSession::parameterUser, username); session->setParameter(SaslClientSession::parameterPassword, hashedPwd); session->initialize(); // set up commands to feed the sasl state machine BSONObj saslFirstCommandPrefix = BSON("copydbsaslstart" << 1 << "fromhost" << fromhost << "fromdb" << fromdb << saslCommandMechanismFieldName << kAuthMechScramSha1); BSONObj saslFollowupCommandPrefix = BSON("copydb" << 1 << "fromhost" << fromhost << "fromdb" << fromdb << "todb" << todb); BSONObj saslCommandPrefix = saslFirstCommandPrefix; BSONObj inputObj = BSON(saslCommandPayloadFieldName << ""); bool isServerDone = false; // send copydbsaslstart, then continue to send copydb until we are done. while (!session->isDone()) { string payload; BSONType type; Status status = saslExtractPayload(inputObj, &payload, &type); if (!status.isOK()) { throw DBException(str::stream() << "sasl session failure: " << status.reason(), 0); } string responsePayload; status = session->step(payload, &responsePayload); if (!status.isOK()) { throw DBException(str::stream() << "sasl session failure: " << status.reason(), 0); } // build command to send to server BSONObjBuilder commandBuilder; commandBuilder.appendElements(saslCommandPrefix); commandBuilder.appendBinData(saslCommandPayloadFieldName, int(responsePayload.size()), BinDataGeneral, responsePayload.c_str()); BSONElement conversationId = inputObj[saslCommandConversationIdFieldName]; if (!conversationId.eoo()) { commandBuilder.append(conversationId); } BSONObj command = commandBuilder.obj(); bool ok = runCommand("admin", command, inputObj); ErrorCodes::Error code = ErrorCodes::fromInt(inputObj[saslCommandCodeFieldName].numberInt()); if (!ok || code != ErrorCodes::OK) { if (code == ErrorCodes::OK) code = ErrorCodes::UnknownError; // attempt to give a sane error message if (inputObj.hasField("errmsg")) { BSONElement e = inputObj.getField("errmsg"); uassert(0, "fromhost " + fromhost + " doesn't support SCRAM-SHA-1, use MONGODB-CR", (e.type() == String && strstr(e.valuestr(), "no such cmd: saslStart"))); } throw OperationException(inputObj); } isServerDone = inputObj[saslCommandDoneFieldName].trueValue(); saslCommandPrefix = saslFollowupCommandPrefix; } if (!isServerDone) { invariant(false); } return true; #endif /* MONGO_SSL */ } invariant(false); } bool DBClientWithCommands::setDbProfilingLevel(const string& dbname, ProfilingLevel level, BSONObj* info) { BSONObj o; if (info == 0) info = &o; if (level) { // Create system.profile collection. If it already exists this does nothing. // TODO: move this into the db instead of here so that all // drivers don't have to do this. string ns = dbname + ".system.profile"; createCollection(ns.c_str(), 1024 * 1024, true, 0, info); } BSONObjBuilder b; b.append("profile", (int)level); return runCommand(dbname, b.done(), *info); } BSONObj getprofilingcmdobj = fromjson("{\"profile\":-1}"); bool DBClientWithCommands::getDbProfilingLevel(const string& dbname, ProfilingLevel& level, BSONObj* info) { BSONObj o; if (info == 0) info = &o; if (runCommand(dbname, getprofilingcmdobj, *info)) { level = (ProfilingLevel)info->getIntField("was"); return true; } return false; } DBClientWithCommands::MROutput DBClientWithCommands::MRInline(BSON("inline" << 1)); BSONObj DBClientWithCommands::mapreduce( const string& ns, const string& jsmapf, const string& jsreducef, Query query, MROutput output) { BSONObjBuilder b; b.append("mapreduce", nsGetCollection(ns)); b.appendCode("map", jsmapf); b.appendCode("reduce", jsreducef); if (!query.obj.isEmpty()) b.append("query", query.getFilter()); if (query.isComplex()) b.appendElements(query.getModifiers()); b.append("out", output.out); BSONObj info; runCommand(nsGetDB(ns), b.done(), info); return info; } void DBClientWithCommands::group(const StringData& ns, const StringData& jsreduce, std::vector* output, const BSONObj& initial, const Query& query, const BSONObj& key, const StringData& finalize) { BSONObjBuilder groupObjBuilder; _buildGroupObj(ns, jsreduce, initial, query, finalize, &groupObjBuilder); if (!key.isEmpty()) groupObjBuilder.append("key", key); _runGroup(ns, groupObjBuilder.obj(), query, output); } void DBClientWithCommands::groupWithKeyFunction(const StringData& ns, const StringData& jsreduce, std::vector* output, const BSONObj& initial, const Query& query, const StringData& jskey, const StringData& finalize) { BSONObjBuilder groupBuilder; _buildGroupObj(ns, jsreduce, initial, query, finalize, &groupBuilder); if (!jskey.empty()) groupBuilder.append("$keyf", jskey); _runGroup(ns, groupBuilder.obj(), query, output); } void DBClientWithCommands::_buildGroupObj(const StringData& ns, const StringData& jsreduce, const BSONObj& initial, const Query& query, const StringData& finalize, BSONObjBuilder* groupObj) { groupObj->append("ns", nsGetCollection(ns.toString())); groupObj->appendCode("$reduce", jsreduce); groupObj->append("initial", initial); if (!query.obj.isEmpty()) groupObj->append("cond", query.getFilter()); if (!finalize.empty()) groupObj->append("finalize", finalize); } void DBClientWithCommands::_runGroup(const StringData& ns, const BSONObj& group, const Query& query, std::vector* output) { BSONObjBuilder commandBuilder; commandBuilder.append("group", group); if (query.isComplex()) commandBuilder.appendElements(query.getModifiers()); BSONObj result; bool ok = runCommand(nsGetDB(ns.toString()), commandBuilder.obj(), result); if (!ok) throw OperationException(result); BSONElement resultArray = result.getField("retval"); BSONObjIterator resultIterator(resultArray.Obj()); while (resultIterator.more()) { output->push_back(resultIterator.next().Obj().getOwned()); } } BSONObj DBClientWithCommands::distinct(const StringData& ns, const StringData& field, const Query& query) { BSONObjBuilder commandBuilder; commandBuilder.append("distinct", nsGetCollection(ns.toString())); commandBuilder.append("key", field); commandBuilder.append("query", query.getFilter()); if (query.isComplex()) commandBuilder.appendElements(query.getModifiers()); BSONObj result; bool ok = runCommand(nsGetDB(ns.toString()), commandBuilder.obj(), result); if (!ok) throw OperationException(result); return result.getField("values").Obj().getOwned(); } void DBClientBase::_findAndModify(const StringData& ns, const BSONObj& query, const BSONObj& update, const BSONObj& sort, bool returnNew, bool upsert, const BSONObj& fields, const WriteConcern* writeConcern, bool bypassDocumentValidation, BSONObjBuilder* out) { BSONObjBuilder commandBuilder; commandBuilder.append("findAndModify", nsGetCollection(ns.toString())); if (update.isEmpty()) commandBuilder.append("remove", true); else commandBuilder.append("update", update); if (!query.isEmpty()) commandBuilder.append("query", query); if (!sort.isEmpty()) commandBuilder.append("sort", sort); if (!fields.isEmpty()) commandBuilder.append("fields", fields); commandBuilder.append("new", returnNew); commandBuilder.append("upsert", upsert); if (getMaxWireVersion() >= 4) { const WriteConcern* operationWriteConcern = writeConcern ? writeConcern : &getWriteConcern(); commandBuilder.append("writeConcern", operationWriteConcern->obj()); } else { uassert(0, "WriteConcern is not supported for findAndModify with this server version.", writeConcern == NULL); } if (bypassDocumentValidation) { uassert( 0, "bypassDocumentValidation is not supported for findAndModify with this server version.", getMaxWireVersion() >= 4); commandBuilder.append(kBypassDocumentValidationKey, true); } BSONObj result; bool ok = runCommand(nsGetDB(ns.toString()), commandBuilder.obj(), result); if (!ok) throw OperationException(result); // Check for any write concern errors WriteResult writeResult; writeResult._mergeWriteConcern(result); writeResult._check(true); out->appendElements(result.getObjectField("value")); } BSONObj DBClientBase::findAndModify(const StringData& ns, const BSONObj& query, const BSONObj& update, bool upsert, bool returnNew, const BSONObj& sort, const BSONObj& fields, const WriteConcern* wc, bool bypassDocumentValidation) { BSONObjBuilder result; _findAndModify( ns, query, update, sort, returnNew, upsert, fields, wc, bypassDocumentValidation, &result); return result.obj(); } BSONObj DBClientBase::findAndRemove(const StringData& ns, const BSONObj& query, const BSONObj& sort, const BSONObj& fields, const WriteConcern* wc) { BSONObjBuilder result; _findAndModify(ns, query, BSONObj(), sort, false, false, fields, wc, false, &result); return result.obj(); } bool DBClientWithCommands::evalDeprecated(const string& dbname, const string& jscode, BSONObj& info, BSONElement& retValue, BSONObj* args, bool nolock) { BSONObjBuilder b; b.appendCode("$eval", jscode); if (args) { b.appendArray("args", *args); } if (nolock) { b.appendBool("nolock", true); } bool ok = runCommand(dbname, b.done(), info); if (ok) retValue = info.getField("retval"); return ok; } bool DBClientWithCommands::evalDeprecated(const string& dbname, const string& jscode) { BSONObj info; BSONElement retValue; return evalDeprecated(dbname, jscode, info, retValue); } list DBClientWithCommands::getDatabaseNames() { BSONObj info; uassert(10005, "listdatabases failed", runCommand("admin", BSON("listDatabases" << 1), info, QueryOption_SlaveOk)); uassert(10006, "listDatabases.databases not array", info["databases"].type() == Array); list names; BSONObjIterator i(info["databases"].embeddedObjectUserCheck()); while (i.more()) { names.push_back(i.next().embeddedObjectUserCheck()["name"].valuestr()); } return names; } list DBClientWithCommands::getCollectionNames(const string& db, const BSONObj& filter) { auto_ptr infos = enumerateCollections(db, filter); uassert(0, "failed to read server response from socket when listing collections", infos.get()); list names; while (infos->more()) { names.push_back(infos->nextSafe()["name"].valuestr()); } return names; } list DBClientWithCommands::getCollectionInfos(const string& db, const BSONObj& filter) { auto_ptr info_cursor = enumerateCollections(db, filter); uassert(0, "failed to read server response from socket when listing collections", info_cursor.get()); list infos; while (info_cursor->more()) { infos.push_back(info_cursor->nextSafe().getOwned()); } return infos; } // Entries in the system.namespaces collection are fully qualified so the database name // must be stripped from the query output for each collection's name bool transformLegacyCollectionInfos(const BSONObj& input, BSONObj* output) { const StringData ns = input["name"].checkAndGetStringData(); // Filter the $ collections out if (ns.find('$') != string::npos) return false; // Strip the database from the name BSONObjBuilder b; b.append("name", ns.substr(ns.find(".") + 1)); b.appendElementsUnique(input); *output = b.obj(); return true; } auto_ptr DBClientWithCommands::_legacyCollectionInfo(const string& db, const BSONObj& filter, int batchSize) { // SERVER-14951 filter for old version fallback needs to db qualify the 'name' element BSONObjBuilder fallbackFilter; if (filter.hasField("name") && filter["name"].type() == String) { fallbackFilter.append("name", db + "." + filter["name"].str()); } fallbackFilter.appendElementsUnique(filter); string namespaces_ns = db + ".system.namespaces"; auto_ptr simple = query(namespaces_ns, fallbackFilter.obj(), 0, 0, 0, QueryOption_SlaveOk, batchSize); simple->shim.reset(new DBClientCursorShimTransform(*simple, transformLegacyCollectionInfos)); simple->nToReturn = 0; simple->setBatchSize(batchSize); return simple; } auto_ptr DBClientWithCommands::enumerateCollections(const string& db, const BSONObj& filter, int batchSize) { const std::string command_ns = db + ".$cmd"; BSONObj cmd = BSON("listCollections" << 1 << "filter" << filter << "cursor" << (batchSize ? BSON("batchSize" << batchSize) : BSONObj())); auto_ptr cursor = this->query(command_ns, cmd, 1, 0, NULL, QueryOption_SlaveOk, 0); if (cursor.get()) { BSONObj result = cursor->peekFirst(); if (isOk(result)) { // Command worked -- we are on MongoDB 2.7.6 or above DBClientCursorShim* cursor_shim; // Select the appropriate shim for this version of MongoDB if (result.hasField("collections")) { // MongoDB 2.7.6 to 2.8.0-rc2 behavior cursor_shim = new DBClientCursorShimArray(*cursor, "collections"); } else { // MongoDB 2.8.0-rc3+ behavior cursor_shim = new DBClientCursorShimCursorID(*cursor); static_cast(cursor_shim)->get_cursor(); } // Insert the shim cursor->shim.reset(cursor_shim); cursor->nToReturn = 0; cursor->setBatchSize(batchSize); } else { // Command failed -- we are either on an older MongoDB or something else happened int error_code = result["code"].numberInt(); string errmsg = result["errmsg"].valuestrsafe(); if ((error_code == ErrorCodes::CommandNotFound) || (error_code == 13390) || (errmsg.find("no such cmd") != string::npos)) { // MongoDB < 2.7.6 behavior -- run legacy code to produce a cursor cursor.reset(_legacyCollectionInfo(db, filter, batchSize).release()); } else { // Something else happened, uassert with the reason uasserted(18630, str::stream() << "listCollections failed: " << result); } } } return cursor; } bool DBClientWithCommands::exists(const string& ns) { BSONObj filter = BSON("name" << nsToCollectionSubstring(ns)); auto_ptr results = enumerateCollections(nsToDatabase(ns), filter); uassert( 0, "failed to read server response from socket when listing collections", results.get()); return results->more(); } /* --- dbclientconnection --- */ void DBClientConnection::_auth(const BSONObj& params) { if (autoReconnect) { /* note we remember the auth info before we attempt to auth -- if the connection is broken, * we will then have it for the next autoreconnect attempt. */ authCache[params[saslCommandUserDBFieldName].str()] = params.getOwned(); } DBClientBase::_auth(params); } /** query N objects from the database into an array. makes sense mostly when you want a small * number of results. if a huge number, use query() and iterate the cursor. */ void DBClientInterface::findN(vector& out, const string& ns, Query query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, int batchSize) { out.reserve(std::min(batchSize, nToReturn)); auto_ptr c = this->query(ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); uassert(10276, str::stream() << "DBClientBase::findN: transport error: " << getServerAddress() << " ns: " << ns << " query: " << query.toString(), c.get()); for (int i = 0; i < nToReturn; i++) { if (!c->more()) break; out.push_back(c->nextSafe().copy()); } } BSONObj DBClientInterface::findOne(const string& ns, const Query& query, const BSONObj* fieldsToReturn, int queryOptions) { vector v; findN(v, ns, query, 1, 0, fieldsToReturn, queryOptions); return v.empty() ? BSONObj() : v[0]; } void DBClientInterface::save(const StringData& ns, const BSONObj& toSave, const WriteConcern* wc) { if (!toSave.hasField("_id")) insert(ns.rawData(), toSave, 0, wc); else update(ns.rawData(), MONGO_QUERY("_id" << toSave.getField("_id")), toSave, true, false, wc); } bool DBClientConnection::connect(const HostAndPort& server, string& errmsg) { _server = server; _serverString = _server.toString(); return _connect(errmsg); } bool DBClientConnection::_connect(string& errmsg) { _serverString = _server.toString(); _serverAddrString.clear(); // we keep around SockAddr for connection life -- maybe MessagingPort // requires that? std::auto_ptr serverSockAddr(new SockAddr(_server.host().c_str(), _server.port())); if (!serverSockAddr->isValid()) { errmsg = str::stream() << "couldn't initialize connection to host " << _server.host().c_str() << ", address is invalid"; return false; } server.reset(serverSockAddr.release()); p.reset(new MessagingPort(_so_timeout, _logLevel)); if (_server.host().empty()) { errmsg = str::stream() << "couldn't connect to server " << toString() << ", host is empty"; return false; } _serverAddrString = server->getAddr(); if (_serverAddrString == "0.0.0.0") { errmsg = str::stream() << "couldn't connect to server " << toString() << ", address resolved to 0.0.0.0"; return false; } if (!p->connect(*server)) { errmsg = str::stream() << "couldn't connect to server " << toString() << ", connection attempt failed"; _failed = true; return false; } else { LOG(1) << "connected to server " << toString() << endl; } #ifdef MONGO_SSL if (client::Options::current().SSLEnabled() && !p->secure(sslManager(), _server.host())) { return false; } #endif BSONObj info; bool worked = simpleCommand("admin", &info, "ismaster"); if (worked) { if (info.hasField("maxBsonObjectSize")) _maxBsonObjectSize = info.getIntField("maxBsonObjectSize"); if (info.hasField("maxMessageSizeBytes")) _maxMessageSizeBytes = info.getIntField("maxMessageSizeBytes"); if (info.hasField("maxWriteBatchSize")) _maxWriteBatchSize = info.getIntField("maxWriteBatchSize"); if (info.hasField("minWireVersion")) _minWireVersion = info.getIntField("minWireVersion"); if (info.hasField("maxWireVersion")) _maxWireVersion = info.getIntField("maxWireVersion"); } return worked; } void DBClientConnection::logout(const string& dbname, BSONObj& info) { authCache.erase(dbname); runCommand(dbname, BSON("logout" << 1), info); } bool DBClientConnection::runCommand(const string& dbname, const BSONObj& cmd, BSONObj& info, int options) { if (DBClientWithCommands::runCommand(dbname, cmd, info, options)) return true; if (!_parentReplSetName.empty()) { handleNotMasterResponse(info["errmsg"]); } return false; } void DBClientConnection::_checkConnection() { if (!_failed) return; if (!autoReconnect) throw SocketException(SocketException::FAILED_STATE, toString()); // Don't hammer reconnects, backoff if needed autoReconnectBackoff.nextSleepMillis(); LOG(_logLevel) << "trying reconnect to " << toString() << endl; string errmsg; _failed = false; if (!_connect(errmsg)) { _failed = true; LOG(_logLevel) << "reconnect " << toString() << " failed " << errmsg << endl; throw SocketException(SocketException::CONNECT_ERROR, toString()); } LOG(_logLevel) << "reconnect " << toString() << " ok" << endl; for (map::const_iterator i = authCache.begin(); i != authCache.end(); i++) { try { DBClientConnection::_auth(i->second); } catch (UserException& ex) { if (ex.getCode() != ErrorCodes::AuthenticationFailed) throw; LOG(_logLevel) << "reconnect: auth failed " << i->second[saslCommandUserDBFieldName] << i->second[saslCommandUserFieldName] << ' ' << ex.what() << std::endl; } } } void DBClientConnection::setSoTimeout(double timeout) { _so_timeout = timeout; if (p) { p->setSocketTimeout(timeout); } } uint64_t DBClientConnection::getSockCreationMicroSec() const { if (p) { return p->getSockCreationMicroSec(); } else { return INVALID_SOCK_CREATION_TIME; } } const uint64_t DBClientBase::INVALID_SOCK_CREATION_TIME = static_cast(0xFFFFFFFFFFFFFFFFULL); DBClientBase::DBClientBase() : _wireProtocolWriter(new WireProtocolWriter(this)), _commandWriter(new CommandWriter(this)) { _writeConcern = WriteConcern::acknowledged; _connectionId = ConnectionIdSequence.fetchAndAdd(1); _maxBsonObjectSize = defaultMaxBsonObjectSize; _maxMessageSizeBytes = defaultMaxMessageSizeBytes; _maxWriteBatchSize = defaultMaxWriteBatchSize; } DBClientBase::~DBClientBase() {} auto_ptr DBClientBase::query(const string& ns, Query query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, int batchSize) { auto_ptr c(new DBClientCursor( this, ns, query.obj, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize)); if (c->init()) return c; return auto_ptr(0); } void DBClientBase::parallelScan(const StringData& ns, int numCursors, std::vector* cursors, stdx::function connectionFactory) { BSONObjBuilder bob; bob.append("parallelCollectionScan", nsGetCollection(ns.toString())); bob.append("numCursors", numCursors); BSONObj result; bool ok = runCommand(nsGetDB(ns.toString()), bob.obj(), result); if (!ok) throw OperationException(result); BSONObj resultArray = result.getObjectField("cursors"); BSONObjIterator arrayIterator(resultArray); while (arrayIterator.more()) { long long cursorId = arrayIterator.next().Obj().getFieldDotted("cursor.id").numberLong(); DBClientBase* conn = NULL; // Attempt to get a connection for this cursor from the user provided connectionFactory try { conn = connectionFactory(); } catch (...) { while (arrayIterator.more()) { try { DBClientCursor killOnServer(this, ns.toString(), cursorId, 0, 0, 0); cursorId = arrayIterator.next().Obj().getFieldDotted("cursor.id").numberLong(); } catch (...) { // ignore any failure to create or destroy the above temporary cursors, they // exist just to attempt to kill the cursors on the server for which we will // not be able to return a cursor to the user } } // Re-throw the users original exception... throw; } // Caller is responsible for cleaning up DBClientCursors DBClientCursor* cursor = new DBClientCursor(conn, ns.toString(), cursorId, 0, 0, 0); cursors->push_back(cursor); } } std::auto_ptr DBClientBase::aggregate(const std::string& ns, const BSONObj& pipeline, const BSONObj* aggregateOptions, int queryOptions) { BSONObjBuilder builder; bool has_cursor = false; builder.append("aggregate", nsToCollectionSubstring(ns)); builder.appendArray("pipeline", pipeline); if (aggregateOptions) { builder.appendElements(*aggregateOptions); if (aggregateOptions->hasField("cursor")) { has_cursor = true; } } if (!has_cursor) { /* If the user hasn't passed a cursor field, try to add one. This * will allow v2.6 servers to return a cursor, rather than an * array, which should be higher performance and would avoid bson * limits on returned sets */ BSONObjBuilder cursor(builder.subobjStart("cursor")); cursor.done(); } BSONObj request = builder.obj(); auto_ptr c = this->query(nsToDatabase(ns) + ".$cmd", request, 1, 0, NULL, queryOptions, 0); if (c.get()) { /* we need this derived class pointer for access to the cursorid * specific get_cursor() method */ DBClientCursorShimCursorID* cursor_shim; c->shim.reset((cursor_shim = new DBClientCursorShimCursorID(*c))); c->nToReturn = 0; if (c->rawMore()) { BSONObj res = cursor_shim->get_cursor(); if (res["ok"].numberInt()) return c; if (((res["code"].numberInt() == 17020) || (res["errmsg"].String() == "unrecognized field \"cursor")) && !has_cursor) { /* the typo is intentional. The server actually returns "\"cursor" * * This fall back is used when we optimistically added a * cursor field hoping to talk to a 2.6 server, but ended * up talking to 2.4. We return the null cursor indicating * error if the user did request a cursor since we cannot * provide one via 2.4 aggregation */ auto_ptr simple = this->query(nsToDatabase(ns) + ".$cmd", request.removeField("cursor"), 1, 0, NULL, queryOptions, 0); simple->shim.reset(new DBClientCursorShimArray(*simple, "result")); simple->nToReturn = 0; return simple; } } } return auto_ptr(NULL); } auto_ptr DBClientBase::getMore(const string& ns, long long cursorId, int nToReturn, int options) { auto_ptr c(new DBClientCursor( this, ns, cursorId, nToReturn < 0 ? abs(nToReturn) : 0, options, abs(nToReturn))); if (c->init()) return c; return auto_ptr(0); } struct DBClientFunConvertor { void operator()(DBClientCursorBatchIterator& i) { while (i.moreInCurrentBatch()) { _f(i.nextSafe()); } } stdx::function _f; }; unsigned long long DBClientBase::query(stdx::function f, const string& ns, Query query, const BSONObj* fieldsToReturn, int queryOptions) { DBClientFunConvertor fun; fun._f = f; stdx::function ptr(fun); return this->query(ptr, ns, query, fieldsToReturn, queryOptions); } unsigned long long DBClientBase::query(stdx::function f, const string& ns, Query query, const BSONObj* fieldsToReturn, int queryOptions) { // mask options queryOptions &= (int)(QueryOption_NoCursorTimeout | QueryOption_SlaveOk); auto_ptr c(this->query(ns, query, 0, 0, fieldsToReturn, queryOptions)); uassert(16090, "socket error for mapping query", c.get()); unsigned long long n = 0; while (c->more()) { DBClientCursorBatchIterator i(*c); f(i); n += i.n(); } return n; } std::auto_ptr DBClientConnection::query(const std::string& ns, Query query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, int batchSize) { checkConnection(); return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); } unsigned long long DBClientConnection::query(stdx::function f, const string& ns, Query query, const BSONObj* fieldsToReturn, int queryOptions) { if (!(availableOptions() & QueryOption_Exhaust)) { return DBClientBase::query(f, ns, query, fieldsToReturn, queryOptions); } // mask options queryOptions &= (int)(QueryOption_NoCursorTimeout | QueryOption_SlaveOk); queryOptions |= (int)QueryOption_Exhaust; auto_ptr c(this->query(ns, query, 0, 0, fieldsToReturn, queryOptions)); uassert(13386, "socket error for mapping query", c.get()); unsigned long long n = 0; try { while (1) { while (c->moreInCurrentBatch()) { DBClientCursorBatchIterator i(*c); f(i); n += i.n(); } if (c->getCursorId() == 0) break; c->exhaustReceiveMore(); } } catch (std::exception&) { /* connection CANNOT be used anymore as more data may be on the way from the server. we have to reconnect. */ _failed = true; p->shutdown(); throw; } return n; } void DBClientBase::_write(const string& ns, const vector& writes, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult) { const WriteConcern* operationWriteConcern = writeConcern ? writeConcern : &getWriteConcern(); if (getMaxWireVersion() >= 2 && operationWriteConcern->requiresConfirmation()) _commandWriter->write( ns, writes, ordered, bypassDocumentValidation, operationWriteConcern, writeResult); else _wireProtocolWriter->write( ns, writes, ordered, bypassDocumentValidation, operationWriteConcern, writeResult); } namespace { struct ScopedWriteOperations { ScopedWriteOperations() {} ~ScopedWriteOperations() { vector::const_iterator it; for (it = ops.begin(); it != ops.end(); ++it) delete *it; } void enqueue(WriteOperation* op) { ops.push_back(op); } std::vector ops; }; } void DBClientBase::insert(const string& ns, BSONObj obj, int flags, const WriteConcern* wc) { vector toInsert; toInsert.push_back(obj); insert(ns, toInsert, flags, wc); } // prefer using the bulk API for this void DBClientBase::insert(const string& ns, const vector& v, int flags, const WriteConcern* wc) { ScopedWriteOperations inserts; vector::const_iterator bsonObjIter; for (bsonObjIter = v.begin(); bsonObjIter != v.end(); ++bsonObjIter) { uassert(0, "document to be inserted exceeds maxBsonObjectSize", (*bsonObjIter).objsize() <= getMaxBsonObjectSize()); inserts.enqueue(new InsertWriteOperation(*bsonObjIter)); } bool ordered = !(flags & InsertOption_ContinueOnError); bool bypassDocumentValidation = flags & InsertOption_BypassDocumentValidation; WriteResult writeResult; _write(ns, inserts.ops, ordered, bypassDocumentValidation, wc, &writeResult); } void DBClientBase::remove(const string& ns, Query obj, bool justOne, const WriteConcern* wc) { remove(ns, obj, justOne & RemoveOption_JustOne, wc); } void DBClientBase::remove(const string& ns, Query obj, int flags, const WriteConcern* wc) { ScopedWriteOperations deletes; uassert(0, "remove selector exceeds maxBsonObjectSize", obj.obj.objsize() <= getMaxBsonObjectSize()); deletes.enqueue(new DeleteWriteOperation(obj.obj, flags)); WriteResult writeResult; _write(ns, deletes.ops, true, false, wc, &writeResult); } void DBClientBase::update( const string& ns, Query query, BSONObj obj, bool upsert, bool multi, const WriteConcern* wc) { int flags = 0; if (upsert) flags |= UpdateOption_Upsert; if (multi) flags |= UpdateOption_Multi; update(ns, query, obj, flags, wc); } void DBClientBase::update( const string& ns, Query query, BSONObj obj, int flags, const WriteConcern* wc) { ScopedWriteOperations updates; uassert(0, "update selector exceeds maxBsonObjectSize", query.obj.objsize() <= getMaxBsonObjectSize()); uassert( 0, "update document exceeds maxBsonObjectSize", obj.objsize() <= getMaxBsonObjectSize()); updates.enqueue(new UpdateWriteOperation(query.obj, obj, flags)); bool bypassDocumentValidation = flags & UpdateOption_BypassDocumentValidation; WriteResult writeResult; _write(ns, updates.ops, true, bypassDocumentValidation, wc, &writeResult); } BulkOperationBuilder DBClientBase::initializeOrderedBulkOp(const std::string& ns) { return BulkOperationBuilder(this, ns, true, false); } BulkOperationBuilder DBClientBase::initializeUnorderedBulkOp(const std::string& ns) { return BulkOperationBuilder(this, ns, false, false); } list DBClientWithCommands::getIndexSpecs(const string& ns, int options) { list specs; auto_ptr specs_cursor = enumerateIndexes(ns, options); if (specs_cursor.get()) { while (specs_cursor->more()) { specs.push_back(specs_cursor->nextSafe().getOwned()); } } return specs; } list DBClientWithCommands::getIndexNames(const std::string& ns, int options) { list indexNames; auto_ptr specs_cursor = enumerateIndexes(ns, options); if (specs_cursor.get()) { while (specs_cursor->more()) { indexNames.push_back(specs_cursor->nextSafe()["name"].valuestr()); } } return indexNames; } auto_ptr DBClientWithCommands::enumerateIndexes(const string& ns, int options, int batchSize) { const NamespaceString nsstring(ns); BSONObj cmd = BSON("listIndexes" << nsstring.coll() << "cursor" << (batchSize ? BSON("batchSize" << batchSize) : BSONObj())); auto_ptr cursor = this->query(nsstring.getCommandNS(), cmd, 1, 0, NULL, options, 0); if (cursor.get()) { BSONObj result = cursor->peekFirst(); if (isOk(result)) { // Command worked -- we are on MongoDB 2.7.6 or above DBClientCursorShim* cursor_shim; // Select the appropriate shim for this version of MongoDB if (result.hasField("indexes")) { // MongoDB 2.7.6 to 2.8.0-rc2 behavior cursor_shim = new DBClientCursorShimArray(*cursor, "indexes"); } else { // MongoDB 2.8.0-rc3+ behavior cursor_shim = new DBClientCursorShimCursorID(*cursor); static_cast(cursor_shim)->get_cursor(); } // Insert the shim cursor->shim.reset(cursor_shim); cursor->nToReturn = 0; cursor->setBatchSize(batchSize); } else { // Command failed -- we are either on an older MongoDB or something else happened int error_code = result["code"].numberInt(); string errmsg = result["errmsg"].valuestrsafe(); if (error_code == ErrorCodes::NamespaceNotFound) { cursor.reset(NULL); } else if ((error_code == ErrorCodes::CommandNotFound) || (error_code == 13390) || (errmsg.find("no such cmd") != string::npos)) { // MongoDB < 2.7.6 behavior -- query system.indexes cursor.reset(query(nsstring.getSystemIndexesCollection(), BSON("ns" << ns), 0, 0, 0, options, batchSize).release()); } else { // Something else happened, uassert with the reason uasserted(18631, str::stream() << "listIndexes failed: " << result); } } } return cursor; } void DBClientWithCommands::dropIndex(const string& ns, BSONObj keys) { dropIndex(ns, genIndexName(keys)); } void DBClientWithCommands::dropIndex(const string& ns, const string& indexName) { BSONObj info; if (!runCommand(nsToDatabase(ns), BSON("deleteIndexes" << nsToCollectionSubstring(ns) << "index" << indexName), info)) { LOG(_logLevel) << "dropIndex failed: " << info << endl; uassert(10007, "dropIndex failed", 0); } } void DBClientWithCommands::dropIndexes(const string& ns) { BSONObj info; uassert(10008, "dropIndexes failed", runCommand(nsToDatabase(ns), BSON("deleteIndexes" << nsToCollectionSubstring(ns) << "index" << "*"), info)); } void DBClientWithCommands::reIndex(const string& ns) { BSONObj info; uassert(0, "reIndex failed", runCommand(nsToDatabase(ns), BSON("reIndex" << nsToCollectionSubstring(ns)), info)); } string DBClientWithCommands::genIndexName(const BSONObj& keys) { stringstream ss; bool first = 1; for (BSONObjIterator i(keys); i.more();) { BSONElement f = i.next(); if (first) first = 0; else ss << "_"; ss << f.fieldName() << "_"; if (f.isNumber()) ss << f.numberInt(); else ss << f.str(); // this should match up with shell command } return ss.str(); } void DBClientWithCommands::createIndex(const StringData& ns, const IndexSpec& descriptor) { const BSONObj descriptorObj = descriptor.toBSON(); BSONObjBuilder command; command.append("createIndexes", nsToCollectionSubstring(ns)); { BSONArrayBuilder indexes(command.subarrayStart("indexes")); indexes.append(descriptorObj); } const BSONObj commandObj = command.done(); BSONObj infoObj; if (!runCommand(nsToDatabase(ns), commandObj, infoObj)) { // If runCommand failed either by returning no code or saying that the command is // not supported, then fall back to inserting into the system.indexes collection. if (!infoObj.hasField("code") || (infoObj["code"].numberInt() == ErrorCodes::CommandNotFound)) { BSONObjBuilder insertCommand; insertCommand.append("ns", ns.toString()); insertCommand.appendElements(descriptorObj); return insert(nsToDatabase(ns) + ".system.indexes", insertCommand.obj()); } // Some other sort of error occurred; raise. throw OperationException(infoObj); } } /* -- DBClientCursor ---------------------------------------------- */ #ifdef MONGO_DEBUG_BUILD #define CHECK_OBJECT(o, msg) massert(10337, (string) "object not valid" + (msg), (o).isValid()) #else #define CHECK_OBJECT(o, msg) #endif void assembleRequest(const string& ns, BSONObj query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, Message& toSend) { CHECK_OBJECT(query, "assembleRequest query"); // see query.h for the protocol we are using here. BufBuilder b; int opts = queryOptions; b.appendNum(opts); b.appendStr(ns); b.appendNum(nToSkip); b.appendNum(nToReturn); query.appendSelfToBufBuilder(b); if (fieldsToReturn) fieldsToReturn->appendSelfToBufBuilder(b); toSend.setData(dbQuery, b.buf(), b.len()); } DBClientConnection::DBClientConnection(bool _autoReconnect, DBClientReplicaSet*, double so_timeout) : _failed(false), autoReconnect(_autoReconnect), autoReconnectBackoff(1000, 2000), _so_timeout(so_timeout) { _numConnections.fetchAndAdd(1); } void DBClientConnection::say(Message& toSend, bool isRetry, string* actualServer) { checkConnection(); try { port().say(toSend); } catch (SocketException&) { _failed = true; throw; } } void DBClientConnection::sayPiggyBack(Message& toSend) { port().piggyBack(toSend); } bool DBClientConnection::recv(Message& m) { if (port().recv(m)) { return true; } _failed = true; return false; } bool DBClientConnection::call(Message& toSend, Message& response, bool assertOk, string* actualServer) { /* todo: this is very ugly messagingport::call returns an error code AND can throw an exception. we should make it return void and just throw an exception anytime it fails */ checkConnection(); try { if (!port().call(toSend, response)) { _failed = true; if (assertOk) uasserted(10278, str::stream() << "dbclient error communicating with server: " << getServerAddress()); return false; } } catch (SocketException&) { _failed = true; throw; } return true; } BSONElement getErrField(const BSONObj& o) { BSONElement first = o.firstElement(); if (strcmp(first.fieldName(), "$err") == 0) return first; // temp - will be DEV only later /*DEV*/ if (1) { BSONElement e = o["$err"]; if (!e.eoo()) { wassert(false); } return e; } return BSONElement(); } bool hasErrField(const BSONObj& o) { return !getErrField(o).eoo(); } void DBClientConnection::checkResponse(const char* data, int nReturned, bool* retry, string* host) { /* check for errors. the only one we really care about at * this stage is "not master" */ *retry = false; *host = _serverString; if (!_parentReplSetName.empty() && nReturned) { verify(data); BSONObj bsonView(data); handleNotMasterResponse(getErrField(bsonView)); } } void DBClientConnection::killCursor(long long cursorId) { StackBufBuilder b; b.appendNum((int)0); // reserved b.appendNum((int)1); // number b.appendNum(cursorId); Message m; m.setData(dbKillCursors, b.buf(), b.len()); if (_lazyKillCursor) sayPiggyBack(m); else say(m); } void DBClientConnection::setParentReplSetName(const string& replSetName) { _parentReplSetName = replSetName; } void DBClientConnection::handleNotMasterResponse(const BSONElement& elemToCheck) { if (!isNotMasterErrorString(elemToCheck)) { return; } MONGO_LOG_COMPONENT(1, logger::LogComponent::kReplication) << "got not master from: " << _serverString << " of repl set: " << _parentReplSetName; ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(_parentReplSetName); if (monitor) { monitor->failedHost(_server); } _failed = true; } #ifdef MONGO_SSL static boost::mutex s_mtx; static SSLManagerInterface* s_sslMgr(NULL); SSLManagerInterface* DBClientConnection::sslManager() { boost::lock_guard lk(s_mtx); if (s_sslMgr) return s_sslMgr; s_sslMgr = getSSLManager(); return s_sslMgr; } #endif AtomicInt32 DBClientConnection::_numConnections; bool DBClientConnection::_lazyKillCursor = true; bool serverAlive(const string& uri) { DBClientConnection c(false, 0, 20); // potentially the connection to server could fail while we're // checking if it's alive - so use timeouts string err; if (!c.connect(HostAndPort(uri), err)) return false; if (!c.simpleCommand("admin", 0, "ping")) return false; return true; } /** @return the database name portion of an ns string */ string nsGetDB(const string& ns) { string::size_type pos = ns.find("."); if (pos == string::npos) return ns; return ns.substr(0, pos); } /** @return the collection name portion of an ns string */ string nsGetCollection(const string& ns) { string::size_type pos = ns.find("."); if (pos == string::npos) return ""; return ns.substr(pos + 1); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient.h000066400000000000000000000043311273231111400233020ustar00rootroot00000000000000/** @file dbclient.h Include this file when writing client C++ applications, to get access to the mongod C++ driver. */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #ifdef MONGO_EXPOSE_MACROS #error dbclient.h is for C++ driver consumer use only #endif // Consumers of the MongoDB C++ client library must define STATIC_LIBMONGOCLIENT when including // this header if they intend to link against the static version of the library. This is best // handled by adding STATIC_LIBMONGOCLIENT to the list of definitions passed on each compile // invocation. #ifndef STATIC_LIBMONGOCLIENT #if defined(_WIN32) && !defined(_DLL) #error "The DLL build of libmongoclient requires consuming code to be built with /MD or /MDd" #endif #endif #if defined(_MSC_VER) #pragma warning(push) // Don't emit deprecation warnings #pragma warning(disable : 4996) #if defined(_DLL) // Don't spam DLL consumers with warnings about STL symbol exports #pragma warning(disable : 4251) #pragma warning(disable : 4275) #endif #endif #if defined(_WIN32) && !defined(_WINSOCK2API_) #error "You must include the windows and windows sockets headers before dbclient.h" #endif #include "mongo/config.h" #include "mongo/client/redef_macros.h" #include "mongo/client/autolib.h" #include "mongo/client/dbclient_rs.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/gridfs.h" #include "mongo/client/init.h" #include "mongo/client/options.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/geo/interface.h" #include "mongo/version.h" #include "mongo/client/undef_macros.h" #if defined(_MSC_VER) #pragma warning(pop) #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient_rs.cpp000066400000000000000000001142711273231111400243460ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/client/dbclient_rs.h" #include #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/builder.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/db/dbmessage.h" #include "mongo/db/jsobj.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" namespace mongo { using std::auto_ptr; using std::endl; using std::map; using std::set; using std::string; using std::vector; namespace { /* * Set of commands that can be used with $readPreference */ set _secOkCmdList; class PopulateReadPrefSecOkCmdList { public: PopulateReadPrefSecOkCmdList() { _secOkCmdList.insert("aggregate"); _secOkCmdList.insert("collStats"); _secOkCmdList.insert("count"); _secOkCmdList.insert("distinct"); _secOkCmdList.insert("dbStats"); _secOkCmdList.insert("explain"); _secOkCmdList.insert("find"); _secOkCmdList.insert("geoNear"); _secOkCmdList.insert("geoSearch"); _secOkCmdList.insert("geoWalk"); _secOkCmdList.insert("group"); _secOkCmdList.insert("text"); _secOkCmdList.insert("parallelCollectionScan"); } } _populateReadPrefSecOkCmdList; /** * Extracts the read preference settings from the query document. Note that this method * assumes that the query is ok for secondaries so it defaults to * ReadPreference_SecondaryPreferred when nothing is specified. Supports the following * format: * * Format A (official format): * { query: , $readPreference: } * * Format B (unofficial internal format from mongos): * { , $queryOptions: { $readPreference: }} * * @param query the raw query document * * @return the read preference setting if a read preference exists, otherwise the default read * preference of Primary_Only. If the tags field was not present, it will contain one * empty tag document {} which matches any tag. * * @throws AssertionException if the read preference object is malformed */ ReadPreferenceSetting* _extractReadPref(const BSONObj& query, int queryOptions) { if (Query::hasReadPreference(query)) { ReadPreference pref = mongo::ReadPreference_SecondaryPreferred; BSONElement readPrefElement; if (query.hasField(Query::ReadPrefField.name())) { readPrefElement = query[Query::ReadPrefField.name()]; } else { readPrefElement = query["$queryOptions"][Query::ReadPrefField.name()]; } uassert(16381, "$readPreference should be an object", readPrefElement.isABSONObj()); const BSONObj& prefDoc = readPrefElement.Obj(); uassert(16382, "mode not specified for read preference", prefDoc.hasField(Query::ReadPrefModeField.name())); const string mode = prefDoc[Query::ReadPrefModeField.name()].String(); if (mode == "primary") { pref = mongo::ReadPreference_PrimaryOnly; } else if (mode == "primaryPreferred") { pref = mongo::ReadPreference_PrimaryPreferred; } else if (mode == "secondary") { pref = mongo::ReadPreference_SecondaryOnly; } else if (mode == "secondaryPreferred") { pref = mongo::ReadPreference_SecondaryPreferred; } else if (mode == "nearest") { pref = mongo::ReadPreference_Nearest; } else { uasserted(16383, str::stream() << "Unknown read preference mode: " << mode); } if (prefDoc.hasField(Query::ReadPrefTagsField.name())) { const BSONElement& tagsElem = prefDoc[Query::ReadPrefTagsField.name()]; uassert(16385, "tags for read preference should be an array", tagsElem.type() == mongo::Array); TagSet tags(BSONArray(tagsElem.Obj().getOwned())); if (pref == mongo::ReadPreference_PrimaryOnly && !tags.getTagBSON().isEmpty()) { uassert(16384, "Only empty tags are allowed with primary read preference", tags.getTagBSON().firstElement().Obj().isEmpty()); } return new ReadPreferenceSetting(pref, tags); } else { return new ReadPreferenceSetting(pref, TagSet()); } } // Default read pref is primary only or secondary preferred with slaveOK ReadPreference pref = queryOptions & QueryOption_SlaveOk ? mongo::ReadPreference_SecondaryPreferred : mongo::ReadPreference_PrimaryOnly; return new ReadPreferenceSetting(pref, TagSet()); } } // namespace using boost::shared_ptr; // -------------------------------- // ----- DBClientReplicaSet --------- // -------------------------------- const size_t DBClientReplicaSet::MAX_RETRY = 3; bool DBClientReplicaSet::_authPooledSecondaryConn = true; DBClientReplicaSet::DBClientReplicaSet(const string& name, const vector& servers, double so_timeout) : _setName(name), _so_timeout(so_timeout) { ReplicaSetMonitor::createIfNeeded(name, set(servers.begin(), servers.end())); } DBClientReplicaSet::~DBClientReplicaSet() { if (_lastSlaveOkConn.get() == _master.get()) { _lastSlaveOkConn.release(); } } ReplicaSetMonitorPtr DBClientReplicaSet::_getMonitor() const { ReplicaSetMonitorPtr rsm = ReplicaSetMonitor::get(_setName, true); // If you can't get a ReplicaSetMonitor then this connection isn't valid uassert(16340, str::stream() << "No replica set monitor active and no cached seed " "found for set: " << _setName, rsm); return rsm; } // This can't throw an exception because it is called in the destructor of ScopedDbConnection string DBClientReplicaSet::getServerAddress() const { ReplicaSetMonitorPtr rsm = ReplicaSetMonitor::get(_setName, true); if (!rsm) { warning() << "Trying to get server address for DBClientReplicaSet, but no " "ReplicaSetMonitor exists for " << _setName << endl; return str::stream() << _setName << "/"; } return rsm->getServerAddress(); } void DBClientReplicaSet::setRunCommandHook(DBClientWithCommands::RunCommandHookFunc func) { // Set the hooks in both our sub-connections and in ourselves. if (_master) { _master->setRunCommandHook(func); } if (_lastSlaveOkConn.get()) { _lastSlaveOkConn->setRunCommandHook(func); } _runCommandHook = func; } void DBClientReplicaSet::setPostRunCommandHook(DBClientWithCommands::PostRunCommandHookFunc func) { // Set the hooks in both our sub-connections and in ourselves. if (_master) { _master->setPostRunCommandHook(func); } if (_lastSlaveOkConn.get()) { _lastSlaveOkConn->setPostRunCommandHook(func); } _postRunCommandHook = func; } // A replica set connection is never disconnected, since it controls its own reconnection // logic. // // Has the side effect of proactively clearing any cached connections which have been // disconnected in the background. bool DBClientReplicaSet::isStillConnected() { if (_master && !_master->isStillConnected()) { resetMaster(); // Don't notify monitor of bg failure, since it's not clear how long ago it happened } if (_lastSlaveOkConn.get() && !_lastSlaveOkConn->isStillConnected()) { resetSlaveOkConn(); // Don't notify monitor of bg failure, since it's not clear how long ago it happened } return true; } // Internal implementation of isSecondaryQuery, takes previously-parsed read preference static bool _isSecondaryQuery(const string& ns, const BSONObj& queryObj, const ReadPreferenceSetting& readPref) { // If the read pref is primary only, this is not a secondary query if (readPref.pref == ReadPreference_PrimaryOnly) return false; if (ns.find(".$cmd") == string::npos) { return true; } // This is a command with secondary-possible read pref // Only certain commands are supported for secondary operation. BSONObj actualQueryObj; if (strcmp(queryObj.firstElement().fieldName(), "query") == 0) { actualQueryObj = queryObj["query"].embeddedObject(); } else { actualQueryObj = queryObj; } const string cmdName = actualQueryObj.firstElementFieldName(); if (_secOkCmdList.count(cmdName) == 1) { return true; } if (cmdName == "mapReduce" || cmdName == "mapreduce") { if (!actualQueryObj.hasField("out")) { return false; } BSONElement outElem(actualQueryObj["out"]); if (outElem.isABSONObj() && outElem["inline"].trueValue()) { return true; } } return false; } bool DBClientReplicaSet::isSecondaryQuery(const string& ns, const BSONObj& queryObj, int queryOptions) { auto_ptr readPref(_extractReadPref(queryObj, queryOptions)); return _isSecondaryQuery(ns, queryObj, *readPref); } DBClientConnection* DBClientReplicaSet::checkMaster() { ReplicaSetMonitorPtr monitor = _getMonitor(); HostAndPort h = monitor->getMasterOrUassert(); if (h == _masterHost && _master) { // a master is selected. let's just make sure connection didn't die if (!_master->isFailed()) return _master.get(); monitor->failedHost(_masterHost); h = monitor->getMasterOrUassert(); // old master failed, try again. } _masterHost = h; ConnectionString connStr(_masterHost); string errmsg; DBClientConnection* newConn = NULL; try { // Needs to perform a dynamic_cast because we need to set the replSet // callback. We should eventually not need this after we remove the // callback. newConn = dynamic_cast(connStr.connect(errmsg, _so_timeout)); } catch (const AssertionException& ex) { errmsg = ex.toString(); } if (newConn == NULL || !errmsg.empty()) { monitor->failedHost(_masterHost); uasserted(ErrorCodes::FailedToSatisfyReadPreference, str::stream() << "can't connect to new replica set master [" << _masterHost.toString() << "]" << (errmsg.empty() ? "" : ", err: ") << errmsg); } resetMaster(); _masterHost = h; _master.reset(newConn); _master->setParentReplSetName(_setName); _master->setRunCommandHook(_runCommandHook); _master->setPostRunCommandHook(_postRunCommandHook); _auth(_master.get()); return _master.get(); } bool DBClientReplicaSet::checkLastHost(const ReadPreferenceSetting* readPref) { // Can't use a cached host if we don't have one. if (!_lastSlaveOkConn.get() || _lastSlaveOkHost.empty()) { return false; } // Don't pin if the readPrefs differ. if (!_lastReadPref || !_lastReadPref->equals(*readPref)) { return false; } // Make sure we don't think the host is down. if (_lastSlaveOkConn->isFailed() || !_getMonitor()->isHostUp(_lastSlaveOkHost)) { invalidateLastSlaveOkCache(); return false; } return true; } void DBClientReplicaSet::_auth(DBClientConnection* conn) { for (map::const_iterator i = _auths.begin(); i != _auths.end(); ++i) { try { conn->auth(i->second); } catch (const UserException&) { warning() << "cached auth failed for set: " << _setName << " db: " << i->second[saslCommandUserDBFieldName].str() << " user: " << i->second[saslCommandUserFieldName].str() << endl; } } } void DBClientReplicaSet::logoutAll(DBClientConnection* conn) { for (map::const_iterator i = _auths.begin(); i != _auths.end(); ++i) { BSONObj response; try { conn->logout(i->first, response); } catch (const UserException&) { warning() << "Failed to logout: " << conn->getServerAddress() << " on db: " << i->first << endl; } } } DBClientConnection& DBClientReplicaSet::masterConn() { return *checkMaster(); } DBClientConnection& DBClientReplicaSet::slaveConn() { shared_ptr readPref( new ReadPreferenceSetting(ReadPreference_SecondaryPreferred, TagSet())); DBClientConnection* conn = selectNodeUsingTags(readPref); uassert(16369, str::stream() << "No good nodes available for set: " << _getMonitor()->getName(), conn != NULL); return *conn; } bool DBClientReplicaSet::connect() { // Returns true if there are any up hosts. const ReadPreferenceSetting anyUpHost(ReadPreference_Nearest, TagSet()); return !_getMonitor()->getHostOrRefresh(anyUpHost).empty(); } static bool isAuthenticationException(const DBException& ex) { return ex.getCode() == ErrorCodes::AuthenticationFailed; } void DBClientReplicaSet::_auth(const BSONObj& params) { // We prefer to authenticate against a primary, but otherwise a secondary is ok too // Empty tag matches every secondary shared_ptr readPref( new ReadPreferenceSetting(ReadPreference_PrimaryPreferred, TagSet())); LOG(3) << "dbclient_rs authentication of " << _getMonitor()->getName() << endl; // NOTE that we retry MAX_RETRY + 1 times, since we're always primary preferred we don't // fallback to the primary. Status lastNodeStatus = Status::OK(); for (size_t retry = 0; retry < MAX_RETRY + 1; retry++) { try { DBClientConnection* conn = selectNodeUsingTags(readPref); if (conn == NULL) { break; } BSONObj interposedParams = params; // The auth mechanism we select is based on the wire version of DBClientReplicaSet - // which doesn't make sense as we need to pick a separate auth mechanism for each host // depending on its own wire version. In particular 3.0+ MongoDB will refuse to // authenticate with MONGODB-CR, so we need to force usage of SCRAM - SHA - 1 if host // has maxWireVersion > 3 if ((conn->getMaxWireVersion() >= 3) && (params[saslCommandMechanismFieldName].str() == "MONGODB-CR")) { BSONObjBuilder interposedParamsBob; interposedParamsBob.append(saslCommandMechanismFieldName, "SCRAM-SHA-1"); interposedParamsBob.appendElementsUnique(params); interposedParams = interposedParamsBob.obj(); } conn->auth(interposedParams); // Cache the new auth information since we now validated it's good _auths[interposedParams[saslCommandUserDBFieldName].str()] = interposedParams.getOwned(); // Ensure the only child connection open is the one we authenticated against - other // child connections may not have full authentication information. // NOTE: _lastSlaveOkConn may or may not be the same as _master dassert(_lastSlaveOkConn.get() == conn || _master.get() == conn); if (conn != _lastSlaveOkConn.get()) { resetSlaveOkConn(); } if (conn != _master.get()) { resetMaster(); } return; } catch (const DBException& ex) { // We care if we can't authenticate (i.e. bad password) in credential params. if (isAuthenticationException(ex)) { throw; } StringBuilder errMsgB; errMsgB << "can't authenticate against replica set node " << _lastSlaveOkHost.toString(); lastNodeStatus = ex.toStatus(errMsgB.str()); LOG(1) << lastNodeStatus.reason() << endl; invalidateLastSlaveOkCache(); } } if (lastNodeStatus.isOK()) { StringBuilder assertMsgB; assertMsgB << "Failed to authenticate, no good nodes in " << _getMonitor()->getName(); uasserted(ErrorCodes::NodeNotFound, assertMsgB.str()); } else { uasserted(lastNodeStatus.code(), lastNodeStatus.reason()); } } void DBClientReplicaSet::logout(const string& dbname, BSONObj& info) { DBClientConnection* priConn = checkMaster(); priConn->logout(dbname, info); _auths.erase(dbname); /* Also logout the cached secondary connection. Note that this is only * needed when we actually have something cached and is last known to be * working. */ if (_lastSlaveOkConn.get() != NULL && !_lastSlaveOkConn->isFailed()) { try { BSONObj dummy; _lastSlaveOkConn->logout(dbname, dummy); } catch (const DBException&) { // Make sure we can't use this connection again. verify(_lastSlaveOkConn->isFailed()); } } } // ------------- simple functions ----------------- void DBClientReplicaSet::insert(const string& ns, BSONObj obj, int flags, const WriteConcern* wc) { checkMaster()->insert(ns, obj, flags, wc); } void DBClientReplicaSet::insert(const string& ns, const vector& v, int flags, const WriteConcern* wc) { checkMaster()->insert(ns, v, flags, wc); } void DBClientReplicaSet::remove(const string& ns, Query obj, int flags, const WriteConcern* wc) { checkMaster()->remove(ns, obj, flags, wc); } void DBClientReplicaSet::update( const string& ns, Query query, BSONObj obj, int flags, const WriteConcern* wc) { return checkMaster()->update(ns, query, obj, flags, wc); } auto_ptr DBClientReplicaSet::query(const string& ns, Query query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, int batchSize) { shared_ptr readPref(_extractReadPref(query.obj, queryOptions)); if (_isSecondaryQuery(ns, query.obj, *readPref)) { LOG(3) << "dbclient_rs query using secondary or tagged node selection in " << _getMonitor()->getName() << ", read pref is " << readPref->toBSON() << " (primary : " << (_master.get() != NULL ? _master->getServerAddress() : "[not cached]") << ", lastTagged : " << (_lastSlaveOkConn.get() != NULL ? _lastSlaveOkConn->getServerAddress() : "[not cached]") << ")" << endl; string lastNodeErrMsg; for (size_t retry = 0; retry < MAX_RETRY; retry++) { try { DBClientConnection* conn = selectNodeUsingTags(readPref); if (conn == NULL) { break; } auto_ptr cursor = conn->query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); return checkSlaveQueryResult(cursor); } catch (const DBException& dbExcep) { StringBuilder errMsgBuilder; errMsgBuilder << "can't query replica set node " << _lastSlaveOkHost.toString() << ": " << causedBy(dbExcep); lastNodeErrMsg = errMsgBuilder.str(); LOG(1) << lastNodeErrMsg << endl; invalidateLastSlaveOkCache(); } } StringBuilder assertMsg; assertMsg << "Failed to do query, no good nodes in " << _getMonitor()->getName(); if (!lastNodeErrMsg.empty()) { assertMsg << ", last error: " << lastNodeErrMsg; } uasserted(16370, assertMsg.str()); } LOG(3) << "dbclient_rs query to primary node in " << _getMonitor()->getName() << endl; return checkMaster()->query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); } BSONObj DBClientReplicaSet::findOne(const string& ns, const Query& query, const BSONObj* fieldsToReturn, int queryOptions) { shared_ptr readPref(_extractReadPref(query.obj, queryOptions)); if (_isSecondaryQuery(ns, query.obj, *readPref)) { LOG(3) << "dbclient_rs findOne using secondary or tagged node selection in " << _getMonitor()->getName() << ", read pref is " << readPref->toBSON() << " (primary : " << (_master.get() != NULL ? _master->getServerAddress() : "[not cached]") << ", lastTagged : " << (_lastSlaveOkConn.get() != NULL ? _lastSlaveOkConn->getServerAddress() : "[not cached]") << ")" << endl; string lastNodeErrMsg; for (size_t retry = 0; retry < MAX_RETRY; retry++) { try { DBClientConnection* conn = selectNodeUsingTags(readPref); if (conn == NULL) { break; } return conn->findOne(ns, query, fieldsToReturn, queryOptions); } catch (const DBException& dbExcep) { StringBuilder errMsgBuilder; errMsgBuilder << "can't findone replica set node " << _lastSlaveOkHost.toString() << ": " << causedBy(dbExcep); lastNodeErrMsg = errMsgBuilder.str(); LOG(1) << lastNodeErrMsg << endl; invalidateLastSlaveOkCache(); } } StringBuilder assertMsg; assertMsg << "Failed to call findOne, no good nodes in " << _getMonitor()->getName(); if (!lastNodeErrMsg.empty()) { assertMsg << ", last error: " << lastNodeErrMsg; } uasserted(16379, assertMsg.str()); } LOG(3) << "dbclient_rs findOne to primary node in " << _getMonitor()->getName() << endl; return checkMaster()->findOne(ns, query, fieldsToReturn, queryOptions); } void DBClientReplicaSet::killCursor(long long cursorID) { // we should never call killCursor on a replica set connection // since we don't know which server it belongs to // can't assume master because of slave ok // and can have a cursor survive a master change verify(0); } void DBClientReplicaSet::isntMaster() { log() << "got not master for: " << _masterHost << endl; // Can't use _getMonitor because that will create a new monitor from the cached seed if // the monitor doesn't exist. ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(_setName); if (monitor) { monitor->failedHost(_masterHost); } resetMaster(); } auto_ptr DBClientReplicaSet::checkSlaveQueryResult( auto_ptr result) { if (result.get() == NULL) return result; BSONObj error; bool isError = result->peekError(&error); if (!isError) return result; // We only check for "not master or secondary" errors here // If the error code here ever changes, we need to change this code also BSONElement code = error["code"]; if (code.isNumber() && code.Int() == NotMasterOrSecondaryCode /* not master or secondary */) { isntSecondary(); throw DBException(str::stream() << "slave " << _lastSlaveOkHost.toString() << " is no longer secondary", 14812); } return result; } void DBClientReplicaSet::isntSecondary() { log() << "slave no longer has secondary status: " << _lastSlaveOkHost << endl; // Failover to next slave _getMonitor()->failedHost(_lastSlaveOkHost); resetSlaveOkConn(); } DBClientConnection* DBClientReplicaSet::selectNodeUsingTags( shared_ptr readPref) { if (checkLastHost(readPref.get())) { LOG(3) << "dbclient_rs selecting compatible last used node " << _lastSlaveOkHost << endl; return _lastSlaveOkConn.get(); } ReplicaSetMonitorPtr monitor = _getMonitor(); HostAndPort selectedNode = monitor->getHostOrRefresh(*readPref); if (selectedNode.empty()) { LOG(3) << "dbclient_rs no compatible node found" << endl; return NULL; } // cleanup the last connection we used. resetSlaveOkConn(); _lastReadPref = readPref; _lastSlaveOkHost = selectedNode; // Primary connection is special because it is the only connection that is // versioned in mongos. Therefore, we have to make sure that this object // maintains only one connection to the primary and use that connection // every time we need to talk to the primary. if (monitor->isPrimary(selectedNode)) { checkMaster(); LOG(3) << "dbclient_rs selecting primary node " << selectedNode << endl; _lastSlaveOkConn.reset(_master.get()); return _master.get(); } // Needs to perform a dynamic_cast because we need to set the replSet // callback. We should eventually not need this after we remove the // callback. std::string errmsg; std::auto_ptr newConn(dynamic_cast( ConnectionString(_lastSlaveOkHost).connect(errmsg, _so_timeout))); // Assert here instead of returning NULL since the contract of this method is such // returning NULL means none of the nodes were good, which is not the case here. uassert(0, str::stream() << "Failed to connect to " << _lastSlaveOkHost.toString() << ": " << errmsg, newConn.get()); _lastSlaveOkConn.reset(newConn.release()); _lastSlaveOkConn->setParentReplSetName(_setName); _lastSlaveOkConn->setRunCommandHook(_runCommandHook); _lastSlaveOkConn->setPostRunCommandHook(_postRunCommandHook); if (_authPooledSecondaryConn) { _auth(_lastSlaveOkConn.get()); } else { // Mongos pooled connections are authenticated through // ShardingConnectionHook::onCreate(). } LOG(3) << "dbclient_rs selecting node " << _lastSlaveOkHost << endl; return _lastSlaveOkConn.get(); } void DBClientReplicaSet::say(Message& toSend, bool isRetry, string* actualServer) { if (!isRetry) _lazyState = LazyState(); const int lastOp = toSend.operation(); if (lastOp == dbQuery) { // TODO: might be possible to do this faster by changing api DbMessage dm(toSend); QueryMessage qm(dm); shared_ptr readPref(_extractReadPref(qm.query, qm.queryOptions)); if (_isSecondaryQuery(qm.ns, qm.query, *readPref)) { LOG(3) << "dbclient_rs say using secondary or tagged node selection in " << _getMonitor()->getName() << ", read pref is " << readPref->toBSON() << " (primary : " << (_master.get() != NULL ? _master->getServerAddress() : "[not cached]") << ", lastTagged : " << (_lastSlaveOkConn.get() != NULL ? _lastSlaveOkConn->getServerAddress() : "[not cached]") << ")" << endl; string lastNodeErrMsg; for (size_t retry = 0; retry < MAX_RETRY; retry++) { _lazyState._retries = retry; try { DBClientConnection* conn = selectNodeUsingTags(readPref); if (conn == NULL) { break; } if (actualServer != NULL) { *actualServer = conn->getServerAddress(); } conn->say(toSend); _lazyState._lastOp = lastOp; _lazyState._secondaryQueryOk = true; _lazyState._lastClient = conn; } catch (const DBException& DBExcep) { StringBuilder errMsgBuilder; errMsgBuilder << "can't callLazy replica set node " << _lastSlaveOkHost.toString() << ": " << causedBy(DBExcep); lastNodeErrMsg = errMsgBuilder.str(); LOG(1) << lastNodeErrMsg << endl; invalidateLastSlaveOkCache(); continue; } return; } StringBuilder assertMsg; assertMsg << "Failed to call say, no good nodes in " << _getMonitor()->getName(); if (!lastNodeErrMsg.empty()) { assertMsg << ", last error: " << lastNodeErrMsg; } uasserted(16380, assertMsg.str()); } } LOG(3) << "dbclient_rs say to primary node in " << _getMonitor()->getName() << endl; DBClientConnection* master = checkMaster(); if (actualServer) *actualServer = master->getServerAddress(); _lazyState._lastOp = lastOp; _lazyState._secondaryQueryOk = false; // Don't retry requests to primary since there is only one host to try _lazyState._retries = MAX_RETRY; _lazyState._lastClient = master; master->say(toSend); return; } bool DBClientReplicaSet::recv(Message& m) { verify(_lazyState._lastClient); // TODO: It would be nice if we could easily wrap a conn error as a result error try { return _lazyState._lastClient->recv(m); } catch (DBException& e) { log() << "could not receive data from " << _lazyState._lastClient->toString() << causedBy(e) << endl; return false; } } void DBClientReplicaSet::checkResponse(const char* data, int nReturned, bool* retry, string* targetHost) { // For now, do exactly as we did before, so as not to break things. In general though, we // should fix this so checkResponse has a more consistent contract. if (!retry) { if (_lazyState._lastClient) return _lazyState._lastClient->checkResponse(data, nReturned); else return checkMaster()->checkResponse(data, nReturned); } *retry = false; if (targetHost && _lazyState._lastClient) *targetHost = _lazyState._lastClient->getServerAddress(); else if (targetHost) *targetHost = ""; if (!_lazyState._lastClient) return; // nReturned == 1 means that we got one result back, which might be an error // nReturned == -1 is a sentinel value for "no data returned" aka (usually) network problem // If neither, this must be a query result so our response is ok wrt the replica set if (nReturned != 1 && nReturned != -1) return; BSONObj dataObj; if (nReturned == 1) dataObj = BSONObj(data); // Check if we should retry here if (_lazyState._lastOp == dbQuery && _lazyState._secondaryQueryOk) { // query could potentially go to a secondary, so see if this is an error (or empty) and // retry if we're not past our retry limit. if (nReturned == -1 /* no result, maybe network problem */ || (hasErrField(dataObj) && !dataObj["code"].eoo() && dataObj["code"].Int() == NotMasterOrSecondaryCode)) { if (_lazyState._lastClient == _lastSlaveOkConn.get()) { isntSecondary(); } else if (_lazyState._lastClient == _master.get()) { isntMaster(); } else { warning() << "passed " << dataObj << " but last rs client " << _lazyState._lastClient->toString() << " is not master or secondary" << endl; } if (_lazyState._retries < static_cast(MAX_RETRY)) { _lazyState._retries++; *retry = true; } else { log() << "too many retries (" << _lazyState._retries << "), could not get data from replica set" << endl; } } } else if (_lazyState._lastOp == dbQuery) { // if query could not potentially go to a secondary, just mark the master as bad if (nReturned == -1 /* no result, maybe network problem */ || (hasErrField(dataObj) && !dataObj["code"].eoo() && dataObj["code"].Int() == NotMasterNoSlaveOkCode)) { if (_lazyState._lastClient == _master.get()) { isntMaster(); } } } } bool DBClientReplicaSet::call(Message& toSend, Message& response, bool assertOk, string* actualServer) { const char* ns = 0; if (toSend.operation() == dbQuery) { // TODO: might be possible to do this faster by changing api DbMessage dm(toSend); QueryMessage qm(dm); ns = qm.ns; shared_ptr readPref(_extractReadPref(qm.query, qm.queryOptions)); if (_isSecondaryQuery(ns, qm.query, *readPref)) { LOG(3) << "dbclient_rs call using secondary or tagged node selection in " << _getMonitor()->getName() << ", read pref is " << readPref->toBSON() << " (primary : " << (_master.get() != NULL ? _master->getServerAddress() : "[not cached]") << ", lastTagged : " << (_lastSlaveOkConn.get() != NULL ? _lastSlaveOkConn->getServerAddress() : "[not cached]") << ")" << endl; for (size_t retry = 0; retry < MAX_RETRY; retry++) { try { DBClientConnection* conn = selectNodeUsingTags(readPref); if (conn == NULL) { return false; } if (actualServer != NULL) { *actualServer = conn->getServerAddress(); } return conn->call(toSend, response, assertOk); } catch (const DBException& dbExcep) { LOG(1) << "can't call replica set node " << _lastSlaveOkHost << ": " << causedBy(dbExcep) << endl; if (actualServer) *actualServer = ""; invalidateLastSlaveOkCache(); } } // Was not able to successfully send after max retries return false; } } LOG(3) << "dbclient_rs call to primary node in " << _getMonitor()->getName() << endl; DBClientConnection* m = checkMaster(); if (actualServer) *actualServer = m->getServerAddress(); if (!m->call(toSend, response, assertOk)) return false; if (ns) { QueryResult::View res = response.singleData().view2ptr(); if (res.getNReturned() == 1) { BSONObj x(res.data()); if (str::contains(ns, "$cmd")) { if (isNotMasterErrorString(x["errmsg"])) isntMaster(); } else { if (isNotMasterErrorString(getErrField(x))) isntMaster(); } } } return true; } void DBClientReplicaSet::invalidateLastSlaveOkCache() { /* This is not wrapped in with if (_lastSlaveOkConn && _lastSlaveOkConn->isFailed()) * because there are certain exceptions that will not make the connection be labeled * as failed. For example, asserts 13079, 13080, 16386 */ _getMonitor()->failedHost(_lastSlaveOkHost); resetSlaveOkConn(); } void DBClientReplicaSet::reset() { resetSlaveOkConn(); _lazyState._lastClient = NULL; _lastReadPref.reset(); } void DBClientReplicaSet::setAuthPooledSecondaryConn(bool setting) { _authPooledSecondaryConn = setting; } void DBClientReplicaSet::resetMaster() { if (_master.get() == _lastSlaveOkConn.get()) { _lastSlaveOkConn.release(); _lastSlaveOkHost = HostAndPort(); } _master.reset(); _masterHost = HostAndPort(); } void DBClientReplicaSet::resetSlaveOkConn() { if (_lastSlaveOkConn.get() == _master.get()) { _lastSlaveOkConn.release(); } else if (_lastSlaveOkConn.get() != NULL) { if (_authPooledSecondaryConn) { logoutAll(_lastSlaveOkConn.get()); } else { // Mongos pooled connections are all authenticated with the same credentials; // so no need to logout. } _lastSlaveOkConn.reset(); } _lastSlaveOkHost = HostAndPort(); } // trying to optimize for the common dont-care-about-tags case. static const BSONArray tagsMatchesAll = BSON_ARRAY(BSONObj()); TagSet::TagSet() : _tags(tagsMatchesAll) {} string readPrefToString(ReadPreference pref) { switch (pref) { case ReadPreference_PrimaryOnly: return "primary only"; case ReadPreference_PrimaryPreferred: return "primary pref"; case ReadPreference_SecondaryOnly: return "secondary only"; case ReadPreference_SecondaryPreferred: return "secondary pref"; case ReadPreference_Nearest: return "nearest"; default: return "Unknown"; } } BSONObj ReadPreferenceSetting::toBSON() const { BSONObjBuilder bob; bob.append("pref", readPrefToString(pref)); bob.append("tags", tags.getTagBSON()); return bob.obj(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient_rs.h000066400000000000000000000306711273231111400240140ustar00rootroot00000000000000/** @file dbclient_rs.h Connect to a Replica Set, from C++ */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/client/dbclientinterface.h" #include "mongo/client/export_macros.h" #include "mongo/util/net/hostandport.h" namespace mongo { class ReplicaSetMonitor; class TagSet; struct ReadPreferenceSetting; typedef boost::shared_ptr ReplicaSetMonitorPtr; /** Use this class to connect to a replica set of servers. The class will manage checking for which server in a replica set is master, and do failover automatically. This can also be used to connect to replica pairs since pairs are a subset of sets On a failover situation, expect at least one operation to return an error (throw an exception) before the failover is complete. Operations are not retried. */ class MONGO_CLIENT_API DBClientReplicaSet : public DBClientBase { public: using DBClientBase::query; using DBClientBase::update; using DBClientBase::remove; /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet * connections. */ DBClientReplicaSet(const std::string& name, const std::vector& servers, double so_timeout = 0); virtual ~DBClientReplicaSet(); /** * Returns false if no member of the set were reachable. This object * can still be used even when false was returned as it will try to * reconnect when you use it later. */ bool connect(); /** * Logs out the connection for the given database. * * @param dbname the database to logout from. * @param info the result object for the logout command (provided for backwards * compatibility with mongo shell) */ virtual void logout(const std::string& dbname, BSONObj& info); // ----------- simple functions -------------- /** throws userassertion "no master found" */ virtual std::auto_ptr query(const std::string& ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); /** throws userassertion "no master found" */ virtual BSONObj findOne(const std::string& ns, const Query& query, const BSONObj* fieldsToReturn = 0, int queryOptions = 0); virtual void insert(const std::string& ns, BSONObj obj, int flags = 0, const WriteConcern* wc = NULL); virtual void insert(const std::string& ns, const std::vector& v, int flags = 0, const WriteConcern* wc = NULL); virtual void remove(const std::string& ns, Query obj, int flags, const WriteConcern* wc = NULL); virtual void update( const std::string& ns, Query query, BSONObj obj, int flags, const WriteConcern* wc = NULL); virtual void killCursor(long long cursorID); // ---- access raw connections ---- /** * WARNING: this method is very dangerous - this object can decide to free the * returned master connection any time. * * @return the reference to the address that points to the master connection. */ DBClientConnection& masterConn(); /** * WARNING: this method is very dangerous - this object can decide to free the * returned master connection any time. This can also unpin the cached * slaveOk/read preference connection. * * @return the reference to the address that points to a secondary connection. */ DBClientConnection& slaveConn(); // ---- callback pieces ------- virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0); virtual bool recv(Message& toRecv); virtual void checkResponse(const char* data, int nReturned, bool* retry = NULL, std::string* targetHost = NULL); /* this is the callback from our underlying connections to notify us that we got a "not master" * error. */ void isntMaster(); /* this is used to indicate we got a "not master or secondary" error from a secondary. */ void isntSecondary(); // ----- status ------ virtual bool isFailed() const { return !_master || _master->isFailed(); } bool isStillConnected(); // ----- informational ---- double getSoTimeout() const { return _so_timeout; } std::string toString() const { return getServerAddress(); } std::string getServerAddress() const; virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; } virtual bool lazySupported() const { return true; } // ---- low level ------ virtual bool call(Message& toSend, Message& response, bool assertOk = true, std::string* actualServer = 0); virtual bool callRead(Message& toSend, Message& response) { return checkMaster()->callRead(toSend, response); } /** * Returns whether a query or command can be sent to secondaries based on the query object * and options. * * @param ns the namespace of the query. * @param queryObj the query object to check. * @param queryOptions the query options * * @return true if the query/cmd could potentially be sent to a secondary, false otherwise */ static bool MONGO_CLIENT_FUNC isSecondaryQuery(const std::string& ns, const BSONObj& queryObj, int queryOptions); virtual void setRunCommandHook(DBClientWithCommands::RunCommandHookFunc func); virtual void setPostRunCommandHook(DBClientWithCommands::PostRunCommandHookFunc func); /** * Performs a "soft reset" by clearing all states relating to secondary nodes and * returning secondary connections to the pool. */ virtual void reset(); /** * @bool setting if true, DBClientReplicaSet connections will make sure that secondary * connections are authenticated and log them before returning them to the pool. */ static void setAuthPooledSecondaryConn(bool setting); virtual int getMaxWireVersion() { return checkMaster()->getMaxWireVersion(); } virtual int getMinWireVersion() { return checkMaster()->getMinWireVersion(); } protected: /** Authorize. Authorizes all nodes as needed */ virtual void _auth(const BSONObj& params); virtual void sayPiggyBack(Message& toSend) { checkMaster()->say(toSend); } private: /** * Used to simplify slave-handling logic on errors * * @return back the passed cursor * @throws DBException if the directed node cannot accept the query because it * is not a master */ std::auto_ptr checkSlaveQueryResult(std::auto_ptr result); DBClientConnection* checkMaster(); /** * Helper method for selecting a node based on the read preference. Will advance * the tag tags object if it cannot find a node that matches the current tag. * * @param readPref the preference to use for selecting a node. * * @return a pointer to the new connection object if it can find a good connection. * Otherwise it returns NULL. * * @throws DBException when an error occurred either when trying to connect to * a node that was thought to be ok or when an assertion happened. */ DBClientConnection* selectNodeUsingTags(boost::shared_ptr readPref); /** * @return true if the last host used in the last slaveOk query is still in the * set and can be used for the given read preference. */ bool checkLastHost(const ReadPreferenceSetting* readPref); /** * Destroys all cached information about the last slaveOk operation. */ void invalidateLastSlaveOkCache(); void _auth(DBClientConnection* conn); /** * Calls logout on the connection for all known database this DBClientRS instance has * logged in. */ void logoutAll(DBClientConnection* conn); /** * Clears the master connection. */ void resetMaster(); /** * Clears the slaveOk connection and returns it to the pool if not the same as _master. */ void resetSlaveOkConn(); /** * Maximum number of retries to make for auto-retry logic when performing a slave ok * operation. */ static const size_t MAX_RETRY; // TODO: remove this when processes other than mongos uses the driver version. static bool _authPooledSecondaryConn; // Throws a DBException if the monitor doesn't exist and there isn't a cached seed to use. ReplicaSetMonitorPtr _getMonitor() const; std::string _setName; HostAndPort _masterHost; boost::scoped_ptr _master; // Last used host in a slaveOk query (can be a primary). HostAndPort _lastSlaveOkHost; // Last used connection in a slaveOk query (can be a primary). // Connection can either be owned here or returned to the connection pool. Note that // if connection is primary, it is owned by _master so it is incorrect to return // it to the pool. std::auto_ptr _lastSlaveOkConn; boost::shared_ptr _lastReadPref; double _so_timeout; // we need to store so that when we connect to a new node on failure // we can re-auth // this could be a security issue, as the password is stored in memory // not sure if/how we should handle std::map _auths; // dbName -> auth parameters protected: /** * for storing (non-threadsafe) information between lazy calls */ class LazyState { public: LazyState() : _lastClient(NULL), _lastOp(-1), _secondaryQueryOk(false), _retries(0) {} DBClientConnection* _lastClient; int _lastOp; bool _secondaryQueryOk; int _retries; } _lazyState; }; /** * A simple object for representing the list of tags requested by a $readPreference. */ class MONGO_CLIENT_API TagSet { public: /** * Creates a TagSet that matches any nodes. * * Do not call during static init. */ TagSet(); /** * Creates a TagSet from a BSONArray of tags. * * @param tags the list of tags associated with this option. This object * will get a shared copy of the list. Therefore, it is important * for the the given tag to live longer than the created tag set. */ explicit TagSet(const BSONArray& tags) : _tags(tags) {} /** * Returns the BSONArray listing all tags that should be accepted. */ const BSONArray& getTagBSON() const { return _tags; } bool operator==(const TagSet& other) const { return _tags == other._tags; } private: BSONArray _tags; }; struct MONGO_CLIENT_API ReadPreferenceSetting { /** * @parm pref the read preference mode. * @param tag the tag set. Note that this object will have the * tag set will have this in a reset state (meaning, this * object's copy of tag will have the iterator in the initial * position). */ ReadPreferenceSetting(ReadPreference pref, const TagSet& tag) : pref(pref), tags(tag) {} inline bool equals(const ReadPreferenceSetting& other) const { return pref == other.pref && tags == other.tags; } BSONObj toBSON() const; const ReadPreference pref; TagSet tags; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient_rs_test.cpp000066400000000000000000000524111273231111400254020ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This file contains tests for DBClientReplicaSet. The tests mocks the servers * the DBClientReplicaSet talks to, so the tests only covers the client side logic. */ #include "mongo/platform/basic.h" #include "mongo/bson/bson_field.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclient_rs.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" #include "mongo/util/assert_util.h" #include #include #include #include namespace { using boost::scoped_ptr; using std::auto_ptr; using std::map; using std::make_pair; using std::pair; using std::string; using std::vector; using mongo::AssertionException; using mongo::BSONArray; using mongo::BSONElement; using mongo::BSONField; using mongo::BSONObj; using mongo::ConnectionString; using mongo::DBClientCursor; using mongo::DBClientReplicaSet; using mongo::HostAndPort; using mongo::HostField; using mongo::IdentityNS; using mongo::MockReplicaSet; using mongo::Query; using mongo::ReadPreference; using mongo::ReplicaSetMonitor; using mongo::TagSet; /** * Basic fixture with one primary and one secondary. */ class BasicRS : public mongo::unittest::Test { protected: void setUp() { ReplicaSetMonitor::initialize(); _replSet.reset(new MockReplicaSet("test", 2)); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); } void tearDown() { ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: boost::scoped_ptr _replSet; }; TEST_F(BasicRS, ReadFromPrimary) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } TEST_F(BasicRS, SecondaryOnly) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } TEST_F(BasicRS, PrimaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); // Need up-to-date view, since either host is valid if view is stale. ReplicaSetMonitor::get(replSet->getSetName())->startOrContinueRefresh().refreshAll(); Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } TEST_F(BasicRS, SecondaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); // Need up-to-date view, since either host is valid if view is stale. ReplicaSetMonitor::get(replSet->getSetName())->startOrContinueRefresh().refreshAll(); Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } /** * Setup for 2 member replica set will all of the nodes down. */ class AllNodesDown : public mongo::unittest::Test { protected: void setUp() { ReplicaSetMonitor::initialize(); _replSet.reset(new MockReplicaSet("test", 2)); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); vector hostList(_replSet->getHosts()); for (vector::const_iterator iter = hostList.begin(); iter != hostList.end(); ++iter) { _replSet->kill(iter->toString()); } } void tearDown() { ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: boost::scoped_ptr _replSet; }; TEST_F(AllNodesDown, ReadFromPrimary) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(AllNodesDown, SecondaryOnly) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(AllNodesDown, PrimaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(AllNodesDown, SecondaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(AllNodesDown, Nearest) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_Nearest, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } /** * Setup for 2 member replica set with the primary down. */ class PrimaryDown : public mongo::unittest::Test { protected: void setUp() { ReplicaSetMonitor::initialize(); _replSet.reset(new MockReplicaSet("test", 2)); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); _replSet->kill(_replSet->getPrimary()); } void tearDown() { ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: boost::scoped_ptr _replSet; }; TEST_F(PrimaryDown, ReadFromPrimary) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(PrimaryDown, SecondaryOnly) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } TEST_F(PrimaryDown, PrimaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } TEST_F(PrimaryDown, SecondaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } TEST_F(PrimaryDown, Nearest) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_Nearest, BSONArray()); auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); } /** * Setup for 2 member replica set with the secondary down. */ class SecondaryDown : public mongo::unittest::Test { protected: void setUp() { ReplicaSetMonitor::initialize(); _replSet.reset(new MockReplicaSet("test", 2)); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); _replSet->kill(_replSet->getSecondaries().front()); } void tearDown() { ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: boost::scoped_ptr _replSet; }; TEST_F(SecondaryDown, ReadFromPrimary) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } TEST_F(SecondaryDown, SecondaryOnly) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); } TEST_F(SecondaryDown, PrimaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } TEST_F(SecondaryDown, SecondaryPreferred) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } TEST_F(SecondaryDown, Nearest) { MockReplicaSet* replSet = getReplSet(); DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); Query query; query.readPref(mongo::ReadPreference_Nearest, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); } /** * Warning: Tests running this fixture cannot be run in parallel with other tests * that uses ConnectionString::setConnectionHook */ class TaggedFiveMemberRS : public mongo::unittest::Test { protected: void setUp() { // Tests for pinning behavior require this. ReplicaSetMonitor::useDeterministicHostSelection = true; // This shuts down the background RSMWatcher thread and prevents it from running. These // tests depend on controlling when the RSMs are updated. ReplicaSetMonitor::initialize(); _replSet.reset(new MockReplicaSet("test", 5)); _originalConnectionHook = ConnectionString::getConnectionHook(); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); { mongo::MockReplicaSet::ReplConfigMap config = _replSet->getReplConfig(); { const string host(_replSet->getPrimary()); map& tag = config[host].tags; tag.clear(); tag["dc"] = "ny"; tag["p"] = "1"; _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } vector secNodes = _replSet->getSecondaries(); vector::const_iterator secIter = secNodes.begin(); { const string host(*secIter); map& tag = config[host].tags; tag.clear(); tag["dc"] = "sf"; tag["s"] = "1"; tag["group"] = "1"; _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); map& tag = config[host].tags; tag.clear(); tag["dc"] = "ma"; tag["s"] = "2"; tag["group"] = "1"; _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); map& tag = config[host].tags; tag.clear(); tag["dc"] = "eu"; tag["s"] = "3"; _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); map& tag = config[host].tags; tag.clear(); tag["dc"] = "jp"; tag["s"] = "4"; _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } _replSet->setConfig(config); } } void tearDown() { ReplicaSetMonitor::useDeterministicHostSelection = false; ConnectionString::setConnectionHook(_originalConnectionHook); ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: ConnectionString::ConnectionHook* _originalConnectionHook; boost::scoped_ptr _replSet; }; TEST_F(TaggedFiveMemberRS, ConnShouldPinIfSameSettings) { MockReplicaSet* replSet = getReplSet(); vector seedList; seedList.push_back(HostAndPort(replSet->getPrimary())); DBClientReplicaSet replConn(replSet->getSetName(), seedList); string dest; { Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); } { Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); const string newDest = doc[HostField.name()].str(); ASSERT_EQUALS(dest, newDest); } } TEST_F(TaggedFiveMemberRS, ConnShouldNotPinIfHostMarkedAsFailed) { MockReplicaSet* replSet = getReplSet(); vector seedList; seedList.push_back(HostAndPort(replSet->getPrimary())); DBClientReplicaSet replConn(replSet->getSetName(), seedList); string dest; { Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); } // This is the only difference from ConnShouldPinIfSameSettings which tests that we *do* pin // in if the host is still marked as up. Note that this only notifies the RSM, and does not // directly effect the DBClientRS. ReplicaSetMonitor::get(replSet->getSetName())->failedHost(HostAndPort(dest)); { Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); const string newDest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, newDest); } } TEST_F(TaggedFiveMemberRS, ConnShouldNotPinIfDiffMode) { MockReplicaSet* replSet = getReplSet(); vector seedList; seedList.push_back(HostAndPort(replSet->getPrimary())); DBClientReplicaSet replConn(replSet->getSetName(), seedList); // Need up-to-date view to ensure there are multiple valid choices. ReplicaSetMonitor::get(replSet->getSetName())->startOrContinueRefresh().refreshAll(); string dest; { Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, replSet->getPrimary()); } { Query query; query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); const string newDest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, newDest); } } TEST_F(TaggedFiveMemberRS, ConnShouldNotPinIfDiffTag) { MockReplicaSet* replSet = getReplSet(); vector seedList; seedList.push_back(HostAndPort(replSet->getPrimary())); DBClientReplicaSet replConn(replSet->getSetName(), seedList); // Need up-to-date view to ensure there are multiple valid choices. ReplicaSetMonitor::get(replSet->getSetName())->startOrContinueRefresh().refreshAll(); string dest; { Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSON_ARRAY(BSON("dc" << "sf"))); // Note: IdentityNS contains the name of the server. auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, replSet->getPrimary()); } { Query query; vector > tagSet; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSON_ARRAY(BSON("group" << 1))); auto_ptr cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); const string newDest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, newDest); } } // Note: slaveConn is dangerous and should be deprecated! Also see SERVER-7801. TEST_F(TaggedFiveMemberRS, SlaveConnReturnsSecConn) { MockReplicaSet* replSet = getReplSet(); vector seedList; seedList.push_back(HostAndPort(replSet->getPrimary())); DBClientReplicaSet replConn(replSet->getSetName(), seedList); // Need up-to-date view since slaveConn() uses SecondaryPreferred, and this test assumes it // knows about at least one secondary. ReplicaSetMonitor::get(replSet->getSetName())->startOrContinueRefresh().refreshAll(); string dest; mongo::DBClientConnection& secConn = replConn.slaveConn(); // Note: IdentityNS contains the name of the server. auto_ptr cursor = secConn.query(IdentityNS, Query()); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); ASSERT_NOT_EQUALS(dest, replSet->getPrimary()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclient_writer.h000066400000000000000000000024551273231111400247030ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/client/write_operation.h" namespace mongo { class WriteConcern; class WriteResult; class DBClientWriter { public: virtual ~DBClientWriter(){}; // This function assumes that WriteOperations have been checked to ensure // involved objects are less than the client's maximum BSON object size. virtual void write(const StringData& ns, const std::vector& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult) = 0; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursor.cpp000066400000000000000000000245241273231111400251010ustar00rootroot00000000000000// dbclient.cpp - connect to a Mongo database as a database, from C++ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursor.h" #include "mongo/db/dbmessage.h" #include "mongo/db/namespace_string.h" #include "mongo/util/debug_util.h" #include "mongo/client/dbclientcursorshim.h" #include "mongo/util/log.h" namespace mongo { using std::auto_ptr; using std::endl; using std::string; using std::vector; DBClientCursor::DBClientCursor(DBClientBase* client, const std::string& _ns, BSONObj _query, int _nToReturn, int _nToSkip, const BSONObj* _fieldsToReturn, int queryOptions, int bs) : _client(client), ns(_ns), query(_query), nToReturn((queryOptions & QueryOption_CursorTailable) ? 0 : _nToReturn), nToSkip(_nToSkip), nReturned(0), fieldsToReturn(_fieldsToReturn), opts(queryOptions), batchSize(bs == 1 ? 2 : bs), resultFlags(0), cursorId(), _ownCursor(true), wasError(false) { _finishConsInit(); } DBClientCursor::DBClientCursor(DBClientBase* client, const std::string& _ns, long long _cursorId, int _nToReturn, int options, int bs) : _client(client), ns(_ns), nToReturn((options & QueryOption_CursorTailable) ? 0 : _nToReturn), nToSkip(0), nReturned(0), fieldsToReturn(0), opts(options), batchSize(bs == 1 ? 2 : bs), resultFlags(0), cursorId(_cursorId), _ownCursor(true), wasError(false) { _finishConsInit(); } void assembleRequest(const string& ns, BSONObj query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, Message& toSend); void DBClientCursor::_finishConsInit() { _originalHost = _client->getServerAddress(); } int DBClientCursor::nextBatchSize() { if (nToReturn == 0) return batchSize; if (batchSize == 0) return nToReturn; return std::min(batchSize, nToReturn); } void DBClientCursor::_assembleInit(Message& toSend) { if (!cursorId) { assembleRequest(ns, query, nextBatchSize(), nToSkip, fieldsToReturn, opts, toSend); } else { BufBuilder b; b.appendNum(opts); b.appendStr(ns); b.appendNum(nextBatchSize()); b.appendNum(cursorId); toSend.setData(dbGetMore, b.buf(), b.len()); } } bool DBClientCursor::init() { Message toSend; _assembleInit(toSend); if (!_client->call(toSend, *batch.m, false, &_originalHost)) { // log msg temp? log() << "DBClientCursor::init call() failed" << endl; return false; } if (batch.m->empty()) { // log msg temp? log() << "DBClientCursor::init message from call() was empty" << endl; return false; } dataReceived(); return true; } void DBClientCursor::initLazy(bool isRetry) { massert(15875, "DBClientCursor::initLazy called on a client that doesn't support lazy", _client->lazySupported()); if (DBClientWithCommands::RunCommandHookFunc hook = _client->getRunCommandHook()) { if (NamespaceString(ns).isCommand()) { BSONObjBuilder bob; bob.appendElements(query); hook(&bob); query = bob.obj(); } } Message toSend; _assembleInit(toSend); _client->say(toSend, isRetry, &_originalHost); } bool DBClientCursor::initLazyFinish(bool& retry) { bool recvd = _client->recv(*batch.m); // If we get a bad response, return false if (!recvd || batch.m->empty()) { if (!recvd) log() << "DBClientCursor::init lazy say() failed" << endl; if (batch.m->empty()) log() << "DBClientCursor::init message from say() was empty" << endl; _client->checkResponse(NULL, -1, &retry, &_lazyHost); return false; } dataReceived(retry, _lazyHost); if (DBClientWithCommands::PostRunCommandHookFunc hook = _client->getPostRunCommandHook()) { if (NamespaceString(ns).isCommand()) { BSONObj cmdResponse = peekFirst(); hook(cmdResponse, _lazyHost); } } return !retry; } bool DBClientCursor::initCommand() { BSONObj res; bool ok = _client->runCommand(nsGetDB(ns), query, res, opts); replyToQuery(0, *batch.m, res); dataReceived(); return ok; } void DBClientCursor::requestMore() { verify(cursorId && batch.pos == batch.nReturned); BufBuilder b; b.appendNum(opts); b.appendStr(ns); b.appendNum(nextBatchSize()); b.appendNum(cursorId); Message toSend; toSend.setData(dbGetMore, b.buf(), b.len()); auto_ptr response(new Message()); _client->call(toSend, *response); this->batch.m = response; dataReceived(); } /** with QueryOption_Exhaust, the server just blasts data at us (marked at end with cursorid==0). */ void DBClientCursor::exhaustReceiveMore() { verify(cursorId && batch.pos == batch.nReturned); verify(!nToReturn); auto_ptr response(new Message()); if (!_client->recv(*response)) { uasserted(16465, "recv failed while exhausting cursor"); } batch.m = response; dataReceived(); } void DBClientCursor::dataReceived(bool& retry, string& host) { QueryResult::View qr = batch.m->singleData().view2ptr(); resultFlags = qr.getResultFlags(); if (qr.getResultFlags() & ResultFlag_ErrSet) { wasError = true; } if (qr.getResultFlags() & ResultFlag_CursorNotFound) { // cursor id no longer valid at the server. verify(qr.getCursorId() == 0); cursorId = 0; // 0 indicates no longer valid (dead) if (!(opts & QueryOption_CursorTailable)) throw UserException( 13127, "getMore: cursor didn't exist on server, possible restart or timeout?"); } if (cursorId == 0 || !(opts & QueryOption_CursorTailable)) { // only set initially: we don't want to kill it on end of data // if it's a tailable cursor cursorId = qr.getCursorId(); } batch.nReturned = qr.getNReturned(); batch.pos = 0; batch.data = qr.data(); _client->checkResponse(batch.data, batch.nReturned, &retry, &host); // watches for "not master" /* this assert would fire the way we currently work: verify( nReturned || cursorId == 0 ); */ } /** If true, safe to call next(). Requests more from server if necessary. */ bool DBClientCursor::rawMore() { DEV _assertIfNull(); if (nToReturn && nReturned >= nToReturn) return false; if (batch.pos < batch.nReturned) return true; if (cursorId == 0) return false; requestMore(); return batch.pos < batch.nReturned; } bool DBClientCursor::more() { DEV _assertIfNull(); if (!_putBack.empty()) return true; if (shim.get()) return shim->more(); return rawMore(); } BSONObj DBClientCursor::rawNext() { DEV _assertIfNull(); uassert(13422, "DBClientCursor next() called but more() is false", batch.pos < batch.nReturned); batch.pos++; BSONObj o(batch.data); batch.data += o.objsize(); /* todo would be good to make data null at end of batch for safety */ return o; } BSONObj DBClientCursor::next() { DEV _assertIfNull(); nReturned++; if (!_putBack.empty()) { BSONObj ret = _putBack.top(); _putBack.pop(); return ret; } if (shim.get()) return shim->next(); return rawNext(); } BSONObj DBClientCursor::nextSafe() { BSONObj o = next(); if (this->wasError && strcmp(o.firstElementFieldName(), "$err") == 0) { std::string s = "nextSafe(): " + o.toString(); LOG(5) << s; uasserted(13106, s); } return o; } void DBClientCursor::peek(vector& v, int atMost) { int m = atMost; /* for( stack::iterator i = _putBack.begin(); i != _putBack.end(); i++ ) { if( m == 0 ) return; v.push_back(*i); m--; n++; } */ int p = batch.pos; const char* d = batch.data; while (m && p < batch.nReturned) { BSONObj o(d); d += o.objsize(); p++; m--; v.push_back(o); } } BSONObj DBClientCursor::peekFirst() { vector v; peek(v, 1); if (v.size() > 0) return v[0]; else return BSONObj(); } bool DBClientCursor::peekError(BSONObj* error) { if (!wasError) return false; vector v; peek(v, 1); verify(v.size() == 1); verify(hasErrField(v[0])); if (error) *error = v[0].getOwned(); return true; } DBClientCursor::~DBClientCursor() { kill(); } void DBClientCursor::kill() { DESTRUCTOR_GUARD( if (cursorId && _ownCursor) { BufBuilder b; b.appendNum((int)0); // reserved b.appendNum((int)1); // number b.appendNum(cursorId); Message m; m.setData(dbKillCursors, b.buf(), b.len()); // Kill the cursor the same way the connection itself would. Usually, non-lazily if (DBClientConnection::getLazyKillCursor()) _client->sayPiggyBack(m); else _client->say(m); } ); // Mark this cursor as dead since we can't do any getMores. cursorId = 0; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursor.h000066400000000000000000000206101273231111400245360ustar00rootroot00000000000000// file dbclientcursor.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/client/dbclientinterface.h" #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/util/net/message.h" namespace mongo { class DBClientCursorShim; class DBClientCursorShimCursorID; class DBClientCursorShimArray; class DBClientCursorShimTransform; /** for mock purposes only -- do not create variants of DBClientCursor, nor hang code here @see DBClientMockCursor */ class MONGO_CLIENT_API DBClientCursorInterface : boost::noncopyable { public: virtual ~DBClientCursorInterface() {} virtual bool more() = 0; virtual BSONObj next() = 0; // TODO bring more of the DBClientCursor interface to here protected: DBClientCursorInterface() {} }; /** Queries return a cursor object */ class MONGO_CLIENT_API DBClientCursor : public DBClientCursorInterface { public: /** If true, safe to call next(). Requests more from server if necessary. */ bool more(); /** If true, there is more in our local buffers to be fetched via next(). Returns false when a getMore request back to server would be required. You can use this if you want to exhaust whatever data has been fetched to the client already but then perhaps stop. */ int objsLeftInBatch() const { _assertIfNull(); return _putBack.size() + batch.nReturned - batch.pos; } bool moreInCurrentBatch() { return objsLeftInBatch() > 0; } /** next @return next object in the result cursor. on an error at the remote server, you will get back: { $err: } if you do not want to handle that yourself, call nextSafe(). Warning: The returned BSONObj will become invalid after the next batch is fetched or when this cursor is destroyed. */ BSONObj next(); /** restore an object previously returned by next() to the cursor */ void putBack(const BSONObj& o) { _putBack.push(o.getOwned()); } /** throws AssertionException if get back { $err : ... } */ BSONObj nextSafe(); /** peek ahead at items buffered for future next() calls. never requests new data from the server. so peek only effective with what is already buffered. WARNING: no support for _putBack yet! */ void peek(std::vector&, int atMost); // Peeks at first element, if exists BSONObj peekFirst(); /** * peek ahead and see if an error occurred, and get the error if so. */ bool peekError(BSONObj* error = NULL); /** iterate the rest of the cursor and return the number if items */ int itcount() { int c = 0; while (more()) { next(); c++; } return c; } /** cursor no longer valid -- use with tailable cursors. note you should only rely on this once more() returns false; 'dead' may be preset yet some data still queued and locally available from the dbclientcursor. */ bool isDead() const { return cursorId == 0; } bool tailable() const { return (opts & QueryOption_CursorTailable) != 0; } /** see ResultFlagType (constants.h) for flag values mostly these flags are for internal purposes - ResultFlag_ErrSet is the possible exception to that */ bool hasResultFlag(int flag) { _assertIfNull(); return (resultFlags & flag) != 0; } /// Change batchSize after construction. Can change after requesting first batch. void setBatchSize(int newBatchSize) { batchSize = newBatchSize; } DBClientCursor(DBClientBase* client, const std::string& _ns, BSONObj _query, int _nToReturn, int _nToSkip, const BSONObj* _fieldsToReturn, int queryOptions, int bs); DBClientCursor(DBClientBase* client, const std::string& _ns, long long _cursorId, int _nToReturn, int options, int _batchSize); virtual ~DBClientCursor(); long long getCursorId() const { return cursorId; } /** by default we "own" the cursor and will send the server a KillCursor message when ~DBClientCursor() is called. This function overrides that. */ void decouple() { _ownCursor = false; } std::string originalHost() const { return _originalHost; } std::string getns() const { return ns; } Message* getMessage() { return batch.m.get(); } /** * Used mainly to run commands on connections that doesn't support lazy initialization and * does not support commands through the call interface. * * @param cmd The BSON representation of the command to send. * * @return true if command was sent successfully */ bool initCommand(); /** * actually does the query */ bool init(); void initLazy(bool isRetry = false); bool initLazyFinish(bool& retry); class Batch : boost::noncopyable { friend class DBClientCursor; std::auto_ptr m; int nReturned; int pos; const char* data; public: Batch() : m(new Message()), nReturned(), pos(), data() {} }; /** * Marks this object as dead and sends the KillCursors message to the server. * * Any errors that result from this are swallowed since this is typically performed as part of * cleanup and a failure to kill the cursor should not result in a failure of the operation * using the cursor. * * Killing an already killed or exhausted cursor does nothing, so it is safe to always call this * if you want to ensure that a cursor is killed. */ void kill(); private: friend class DBClientBase; friend class DBClientConnection; friend class DBClientCursorShimCursorID; friend class DBClientCursorShimArray; friend class DBClientCursorShimTransform; friend class DBClientWithCommands; int nextBatchSize(); void _finishConsInit(); BSONObj rawNext(); bool rawMore(); std::auto_ptr shim; Batch batch; DBClientBase* _client; std::string _originalHost; std::string ns; BSONObj query; int nToReturn; int nToSkip; long long nReturned; const BSONObj* fieldsToReturn; int opts; int batchSize; std::stack _putBack; int resultFlags; long long cursorId; bool _ownCursor; // see decouple() std::string _scopedHost; std::string _lazyHost; bool wasError; void dataReceived() { bool retry; std::string lazyHost; dataReceived(retry, lazyHost); } void dataReceived(bool& retry, std::string& lazyHost); void requestMore(); void exhaustReceiveMore(); // for exhaust // Don't call from a virtual function void _assertIfNull() const { uassert(13348, "connection died", this); } // non-copyable , non-assignable DBClientCursor(const DBClientCursor&); DBClientCursor& operator=(const DBClientCursor&); // init pieces void _assembleInit(Message& toSend); }; /** iterate over objects in current batch only - will not cause a network call */ class MONGO_CLIENT_API DBClientCursorBatchIterator { public: DBClientCursorBatchIterator(DBClientCursor& c) : _c(c), _n() {} bool moreInCurrentBatch() { return _c.moreInCurrentBatch(); } BSONObj nextSafe() { massert(13383, "BatchIterator empty", moreInCurrentBatch()); ++_n; return _c.nextSafe(); } int n() const { return _n; } private: DBClientCursor& _c; int _n; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshim.h000066400000000000000000000021741273231111400254240ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/bson/bsonobj.h" namespace mongo { /** DBClientCursorShim provides an abstract interface for providing * polymorphic cursors. When a shim is attached to a DBClientCursor, the * shim intercepts next() and more() calls. These methods may call through * to the underlying cursor object via rawNext() and rawMore(), or handle * them entirely themselves. */ class DBClientCursorShim { public: virtual BSONObj next() = 0; virtual bool more() = 0; virtual ~DBClientCursorShim() {} }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimarray.cpp000066400000000000000000000032331273231111400270130ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursorshimarray.h" #include "mongo/client/dbclientcursor.h" namespace mongo { DBClientCursorShimArray::DBClientCursorShimArray(DBClientCursor& c, const std::string& arrayField) : cursor(c), iter(NULL, NULL), has_array(false), array_field(arrayField) {} bool DBClientCursorShimArray::more() { bool r = false; if (!has_array) { if (cursor.rawMore()) { BSONObj val = cursor.rawNext(); if (val.hasField(array_field)) { BSONObj arr = val[array_field].Obj(); if (!arr.isEmpty()) { iter = BSONObjIterator(arr); r = true; } } } has_array = true; } else { r = iter.more(); } return r; } BSONObj DBClientCursorShimArray::next() { BSONObj b; if (!has_array) { uassert(0, "DBClientCursorShimArray next() called but more() is false", more()); } else { b = iter.next().Obj(); } return b; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimarray.h000066400000000000000000000024211273231111400264560ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclientcursorshim.h" #include "mongo/bson/bsonobjiterator.h" namespace mongo { class DBClientCursor; /** DBClientCursorShimArray implements the shim interface over an array of * bson obj's. This is useful for providing a cursor when we receive only * a single batch, as in the 2.4 aggregate command reply */ class DBClientCursorShimArray : public DBClientCursorShim { public: DBClientCursorShimArray(DBClientCursor& c, const std::string& arrayField); virtual BSONObj next(); virtual bool more(); private: DBClientCursor& cursor; BSONObjIterator iter; bool has_array; const std::string array_field; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimcursorid.cpp000066400000000000000000000033301273231111400275250ustar00rootroot00000000000000/* Copyright 2014 Mongodb Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientcursorshimarray.h" #include "mongo/client/dbclientcursorshimcursorid.h" namespace mongo { DBClientCursorShimCursorID::DBClientCursorShimCursorID(DBClientCursor& c) : cursor(c), iter(NULL, NULL), in_first_batch(false) {} BSONObj DBClientCursorShimCursorID::get_cursor() { BSONObj b = cursor.rawNext(); BSONElement ele = b["cursor"]; if (!ele.eoo()) { cursor.cursorId = ele["id"].Long(); cursor.ns = ele["ns"].String(); if (!ele["firstBatch"].eoo()) { iter = BSONObjIterator(ele["firstBatch"].Obj()); in_first_batch = true; } } return b; } bool DBClientCursorShimCursorID::more() { if (in_first_batch) { if (iter.more()) return true; in_first_batch = false; if (!cursor.cursorId) return false; } return cursor.rawMore(); } BSONObj DBClientCursorShimCursorID::next() { if (in_first_batch && iter.more()) return iter.next().Obj(); return cursor.rawNext(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimcursorid.h000066400000000000000000000024271273231111400272000ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclientcursorshim.h" #include "mongo/bson/bsonobjiterator.h" namespace mongo { class DBClientCursor; /** DBClientCursorShimCursorID implements the shim interface over a cursor * reply document, rather than the traditional OP_REPLY. It additionally * handles a possible initial firstBatch which is part of the 2.6 aggregate * command api. */ class DBClientCursorShimCursorID : public DBClientCursorShim { public: DBClientCursorShimCursorID(DBClientCursor& c); virtual BSONObj next(); virtual bool more(); BSONObj get_cursor(); private: DBClientCursor& cursor; BSONObjIterator iter; bool in_first_batch; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimtransform.cpp000066400000000000000000000023601273231111400277100ustar00rootroot00000000000000/* Copyright 2014 Mongodb Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursorshimtransform.h" #include "mongo/client/dbclientcursor.h" namespace mongo { DBClientCursorShimTransform::DBClientCursorShimTransform( DBClientCursor& c, const stdx::function& transformation) : cursor(c), transformation(transformation) {} bool DBClientCursorShimTransform::more() { while (cursor.rawMore()) { if (transformation(cursor.rawNext(), &nextDoc)) return true; } return false; } BSONObj DBClientCursorShimTransform::next() { return nextDoc; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientcursorshimtransform.h000066400000000000000000000024641273231111400273620ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclientcursorshim.h" #include "mongo/stdx/functional.h" namespace mongo { class DBClientCursor; /** * DBClientCursorShimTransform implements the shim interface over a cursor * reply document by allowing a transformation to be applied. */ class DBClientCursorShimTransform : public DBClientCursorShim { public: DBClientCursorShimTransform( DBClientCursor& c, const stdx::function& transformation); virtual BSONObj next(); virtual bool more(); private: DBClientCursor& cursor; stdx::function transformation; BSONObj nextDoc; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientinterface.h000066400000000000000000002153561273231111400251760ustar00rootroot00000000000000/** @file dbclientinterface.h Core MongoDB C++ driver interfaces are defined here. */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/config.h" #include "mongo/base/string_data.h" #include "mongo/client/bulk_operation_builder.h" #include "mongo/client/exceptions.h" #include "mongo/client/export_macros.h" #include "mongo/client/index_spec.h" #include "mongo/client/write_concern.h" #include "mongo/client/write_options.h" #include "mongo/db/jsobj.h" #include "mongo/logger/log_severity.h" #include "mongo/platform/atomic_word.h" #include "mongo/stdx/functional.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/message.h" #include "mongo/util/net/message_port.h" namespace mongo { /** the query field 'options' can have these bits set: */ enum MONGO_CLIENT_API QueryOptions { /** Tailable means cursor is not closed when the last data is retrieved. rather, the cursor * marks the final object's position. you can resume using the cursor later, from where it was located, if more data were received. Set on dbQuery and dbGetMore. like any "latent cursor", the cursor may become invalid at some point -- for example if that final object it references were deleted. Thus, you should be prepared to requery if you get back ResultFlag_CursorNotFound. */ QueryOption_CursorTailable = 1 << 1, /** allow query of replica slave. normally these return an error except for namespace "local". */ QueryOption_SlaveOk = 1 << 2, // findingStart mode is used to find the first operation of interest when // we are scanning through a repl log. For efficiency in the common case, // where the first operation of interest is closer to the tail than the head, // we start from the tail of the log and work backwards until we find the // first operation of interest. Then we scan forward from that first operation, // actually returning results to the client. During the findingStart phase, // we release the db mutex occasionally to avoid blocking the db process for // an extended period of time. QueryOption_OplogReplay = 1 << 3, /** The server normally times out idle cursors after an inactivity period to prevent excess * memory uses Set this option to prevent that. */ QueryOption_NoCursorTimeout = 1 << 4, /** Use with QueryOption_CursorTailable. If we are at the end of the data, block for a while * rather than returning no data. After a timeout period, we do return as normal. */ QueryOption_AwaitData = 1 << 5, /** Stream the data down full blast in multiple "more" packages, on the assumption that the * client will fully read all data queried. Faster when you are pulling a lot of data and know * you want to pull it all down. Note: it is not allowed to not read all the data unless you * close the connection. Use the query( stdx::function f, ... ) version of the connection's query() method, and it will take care of all the details for you. */ QueryOption_Exhaust = 1 << 6, /** When sharded, this means its ok to return partial results Usually we will fail a query if all required shards aren't up If this is set, it'll be a partial result set */ QueryOption_PartialResults = 1 << 7, QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOption_AwaitData | QueryOption_Exhaust | QueryOption_PartialResults, }; /** * Start from *top* of bits, these are generic write options that apply to all */ enum MONGO_CLIENT_API WriteOptions { /** logical writeback option */ WriteOption_FromWriteback = 1 << 31 }; // // For legacy reasons, the reserved field pre-namespace of certain types of messages is used // to store options as opposed to the flags after the namespace. This should be transparent to // the api user, but we need these constants to disassemble/reassemble the messages correctly. // enum MONGO_CLIENT_API ReservedOptions { Reserved_InsertOption_ContinueOnError = 1 << 0, Reserved_FromWriteback = 1 << 1 }; enum MONGO_CLIENT_API ReadPreference { /** * Read from primary only. All operations produce an error (throw an * exception where applicable) if primary is unavailable. Cannot be * combined with tags. */ ReadPreference_PrimaryOnly = 0, /** * Read from primary if available, otherwise a secondary. Tags will * only be applied in the event that the primary is unavailable and * a secondary is read from. In this event only secondaries matching * the tags provided would be read from. */ ReadPreference_PrimaryPreferred, /** * Read from secondary if available, otherwise error. */ ReadPreference_SecondaryOnly, /** * Read from a secondary if available, otherwise read from the primary. */ ReadPreference_SecondaryPreferred, /** * Read from any member. */ ReadPreference_Nearest, }; class MONGO_CLIENT_API DBClientBase; class MONGO_CLIENT_API DBClientConnection; /** * ConnectionString can parse MongoDB URIs with the following format: * * mongodb://[usr:pwd@]host1[:port1]...[,hostN[:portN]]][/[db][?options]] * * For a complete list of URI string options, see * https://wiki.mongodb.com/display/DH/Connection+String+Format * * Examples: * * A replica set with three members (one running on default port 27017): * string uri = mongodb://localhost,localhost:27018,localhost:27019 * * Authenticated connection to db 'bedrock' with user 'barney' and pwd 'rubble': * string url = mongodb://barney:rubble@localhost/bedrock * * Use parse() to parse the url, then validate and connect: * string errmsg; * ConnectionString cs = ConnectionString::parse( url, errmsg ); * if ( ! cs.isValid() ) throw "bad connection string: " + errmsg; * DBClientBase * conn = cs.connect( errmsg ); * * NOTE: * * The 'rs_name/host1:port,host2:port' format has been deprecated, and parse() * will no longer recognize this as a valid URI. To use the deprecated format, * use parseDeprecated() instead. */ class MONGO_CLIENT_API ConnectionString { public: enum ConnectionType { INVALID, MASTER, PAIR, SET, CUSTOM }; ConnectionString() { _type = INVALID; } // Note: This should only be used for direct connections to a single server. For replica // set and SyncClusterConnections, use ConnectionString::parse. ConnectionString(const HostAndPort& server) { _type = MASTER; _servers.push_back(server); _finishInit(); } ConnectionString(ConnectionType type, const std::string& s, const std::string& setName = "") { _type = type; _setName = setName; _fillServers(s); switch (_type) { case MASTER: verify(_servers.size() == 1); break; case SET: verify(_setName.size()); verify(_servers.size() >= 1); // 1 is ok since we can derive break; case PAIR: verify(_servers.size() == 2); break; default: verify(_servers.size() > 0); } _finishInit(); } ConnectionString(const std::string& s, ConnectionType favoredMultipleType) { _type = INVALID; _fillServers(s); if (_type != INVALID) { // set already } else if (_servers.size() == 1) { _type = MASTER; } else { _type = favoredMultipleType; verify(_type == SET); } _finishInit(); } bool isValid() const { return _type != INVALID; } std::string toString() const { return _string; } DBClientBase* connect(std::string& errmsg, double socketTimeout = 0) const; std::string getSetName() const { return _setName; } const std::vector& getServers() const { return _servers; } ConnectionType type() const { return _type; } const std::string& getUser() const { return _user; } const std::string& getPassword() const { return _password; } const BSONObj& getOptions() const { return _options; } const std::string& getDatabase() const { return _database; } /** * This returns true if this and other point to the same logical entity. * For single nodes, thats the same address. * For replica sets, thats just the same replica set name. * For pair (deprecated) or sync cluster connections, that's the same hosts in any ordering. */ bool sameLogicalEndpoint(const ConnectionString& other) const; static ConnectionString MONGO_CLIENT_FUNC parse(const std::string& address, std::string& errmsg); static ConnectionString MONGO_CLIENT_FUNC parseDeprecated(const std::string& address, std::string& errmsg); static std::string MONGO_CLIENT_FUNC typeToString(ConnectionType type); // // Allow overriding the default connection behavior // This is needed for some tests, which otherwise would fail because they are unable to contact // the correct servers. // class ConnectionHook { public: virtual ~ConnectionHook() {} // Returns an alternative connection object for a string virtual DBClientBase* connect(const ConnectionString& c, std::string& errmsg, double socketTimeout) = 0; }; static void setConnectionHook(ConnectionHook* hook) { boost::lock_guard lk(_connectHookMutex); _connectHook = hook; } static ConnectionHook* getConnectionHook() { boost::lock_guard lk(_connectHookMutex); return _connectHook; } // Allows ConnectionStrings to be stored more easily in sets/maps bool operator<(const ConnectionString& other) const { return _string < other._string; } // // FOR TESTING ONLY - useful to be able to directly mock a connection string without // including the entire client library. // static ConnectionString mock(const HostAndPort& server) { ConnectionString connStr; connStr._servers.push_back(server); connStr._string = server.toString(); return connStr; } private: ConnectionString(ConnectionType type, const std::string& user, const std::string& password, const std::string& servers, const std::string& database, const std::string& setName, const BSONObj& options) : _type(type), _servers(), _setName(setName), _user(user), _password(password), _database(database), _options(options) { _fillServers(servers, false); switch (_type) { case MASTER: verify(_servers.size() == 1); break; case SET: verify(_setName.size()); verify(_servers.size() >= 1); // 1 is ok since we can derive break; case PAIR: verify(_servers.size() == 2); break; default: verify(_servers.size() > 0); } _finishInit(); } static ConnectionString _parseURL(const std::string& url, std::string& errmsg); void _fillServers(std::string s, bool legacy = true); void _finishInit(); BSONObj _makeAuthObjFromOptions(int maxWireVersion) const; ConnectionType _type; std::vector _servers; std::string _string; std::string _setName; std::string _user; std::string _password; std::string _database; BSONObj _options; static boost::mutex _connectHookMutex; static ConnectionHook* _connectHook; }; class BSONObj; class DBClientCursor; class DBClientCursorBatchIterator; /** Represents a Mongo query expression. Typically one uses the MONGO_QUERY(...) macro to construct * a Query object. Examples: MONGO_QUERY( "age" << 33 << "school" << "UCLA" ).sort("name") MONGO_QUERY( "age" << GT << 30 << LT << 50 ) */ class MONGO_CLIENT_API Query { public: static const BSONField ReadPrefField; static const BSONField ReadPrefModeField; static const BSONField ReadPrefTagsField; BSONObj obj; Query() : obj(BSONObj()) {} Query(const BSONObj& b) : obj(b) {} Query(const std::string& json); Query(const char* json); /** Add a sort (ORDER BY) criteria to the query expression. @param sortPattern the sort order template. For example to order by name ascending, time descending: { name : 1, ts : -1 } i.e. BSON( "name" << 1 << "ts" << -1 ) or fromjson(" name : 1, ts : -1 ") */ Query& sort(const BSONObj& sortPattern); /** Add a sort (ORDER BY) criteria to the query expression. This version of sort() assumes you want to sort on a single field. @param asc = 1 for ascending order asc = -1 for descending order */ Query& sort(const std::string& field, int asc = 1) { sort(BSON(field << asc)); return *this; } /** Provide a hint to the query. @param keyPattern Key pattern for the index to use. Example: hint("{ts:1}") */ Query& hint(BSONObj keyPattern); Query& hint(const std::string& indexName); /** * Specifies a cumulative time limit in milliseconds for processing an operation. * MongoDB will interrupt the operation at the earliest following interrupt point. */ Query& maxTimeMs(int millis); /** Provide min and/or max index limits for the query. min <= x < max */ Query& minKey(const BSONObj& val); /** max is exclusive */ Query& maxKey(const BSONObj& val); /** Return explain information about execution of this query instead of the actual query * results. Normally it is easier to use the mongo shell to run db.find(...).explain(). */ Query& explain(); /** Use snapshot mode for the query. Snapshot mode assures no duplicates are returned, or * objects missed, which were present at both the start and end of the query's execution (if an * object is new during the query, or deleted during the query, it may or may not be returned, * even with snapshot mode). Note that short query responses (less than 1MB) are always effectively snapshotted. Currently, snapshot mode may not be used with sorting or explicit hints. */ Query& snapshot(); /** Queries to the Mongo database support a $where parameter option which contains a javascript function that is evaluated to see whether objects being queried match its criteria. Use this helper to append such a function to a query object. Your query may also contain other traditional Mongo query terms. @param jscode The javascript function to evaluate against each potential object match. The function must return true for matched objects. Use the this variable to inspect the current object. @param scope SavedContext for the javascript object. List in a BSON object any variables you would like defined when the jscode executes. One can think of these as "bind variables". Examples: conn.findOne("test.coll", Query("{a:3}").where("this.b == 2 || this.c == 3")); Query badBalance = Query().where("this.debits - this.credits < 0"); */ Query& where(const std::string& jscode, BSONObj scope); Query& where(const std::string& jscode) { return where(jscode, BSONObj()); } /** * Sets the read preference for this query. * * @param pref the read preference mode for this query. * @param tags the set of tags to use for this query. */ Query& readPref(ReadPreference pref, const BSONArray& tags); /** * @return true if this query has an orderby, hint, or some other field */ bool isComplex(bool* hasDollar = 0) const; BSONObj getModifiers() const; static bool MONGO_CLIENT_FUNC isComplex(const BSONObj& obj, bool* hasDollar = 0); BSONObj getFilter() const; BSONObj getSort() const; BSONElement getHint() const; BSONObj getReadPref() const; int getMaxTimeMs() const; bool isExplain() const; /** * @return true if the query object contains a read preference specification object. */ static bool MONGO_CLIENT_FUNC hasReadPreference(const BSONObj& queryObj); bool hasReadPreference() const; bool hasHint() const; bool hasMaxTimeMs() const; std::string toString() const; operator std::string() const { return toString(); } private: void makeComplex(); template void appendComplex(const char* fieldName, const T& val) { makeComplex(); BSONObjBuilder b; b.appendElements(obj); b.append(fieldName, val); obj = b.obj(); } }; /** * Represents a full query description, including all options required for the query to be passed on * to other hosts */ class MONGO_CLIENT_API QuerySpec { std::string _ns; int _ntoskip; int _ntoreturn; int _options; BSONObj _query; BSONObj _fields; Query _queryObj; public: QuerySpec(const std::string& ns, const BSONObj& query, const BSONObj& fields, int ntoskip, int ntoreturn, int options) : _ns(ns), _ntoskip(ntoskip), _ntoreturn(ntoreturn), _options(options), _query(query.getOwned()), _fields(fields.getOwned()), _queryObj(_query) {} QuerySpec() {} bool isEmpty() const { return _ns.size() == 0; } bool isExplain() const { return _queryObj.isExplain(); } BSONObj filter() const { return _queryObj.getFilter(); } BSONElement hint() const { return _queryObj.getHint(); } BSONObj sort() const { return _queryObj.getSort(); } BSONObj query() const { return _query; } BSONObj fields() const { return _fields; } BSONObj* fieldsData() { return &_fields; } // don't love this, but needed downstrem const BSONObj* fieldsPtr() const { return &_fields; } std::string ns() const { return _ns; } int ntoskip() const { return _ntoskip; } int ntoreturn() const { return _ntoreturn; } int options() const { return _options; } void setFields(BSONObj& o) { _fields = o.getOwned(); } std::string toString() const { return str::stream() << "QSpec " << BSON("ns" << _ns << "n2skip" << _ntoskip << "n2return" << _ntoreturn << "options" << _options << "query" << _query << "fields" << _fields); } }; /** Typically one uses the MONGO_QUERY(...) macro to construct a Query object. Example: MONGO_QUERY( "age" << 33 << "school" << "UCLA" ) */ #define MONGO_QUERY(x) ::mongo::Query(BSON(x)) // Useful utilities for namespaces /** @return the database name portion of an ns string */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC nsGetDB(const std::string& ns); /** @return the collection name portion of an ns string */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC nsGetCollection(const std::string& ns); /** interface that handles communication with the db */ class MONGO_CLIENT_API DBConnector { public: virtual ~DBConnector() {} /** actualServer is set to the actual server where they call went if there was a choice * (SlaveOk) */ virtual bool call(Message& toSend, Message& response, bool assertOk = true, std::string* actualServer = 0) = 0; virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0) = 0; virtual void sayPiggyBack(Message& toSend) = 0; /* used by QueryOption_Exhaust. To use that your subclass must implement this. */ virtual bool recv(Message& m) { verify(false); return false; } // In general, for lazy queries, we'll need to say, recv, then checkResponse virtual void checkResponse(const char* data, int nReturned, bool* retry = NULL, std::string* targetHost = NULL) { if (retry) *retry = false; if (targetHost) *targetHost = ""; } virtual bool lazySupported() const = 0; }; /** The interface that any db connection should implement */ class MONGO_CLIENT_API DBClientInterface : boost::noncopyable { public: virtual std::auto_ptr query(const std::string& ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0) = 0; virtual void insert(const std::string& ns, BSONObj obj, int flags = 0, const WriteConcern* wc = NULL) = 0; virtual void insert(const std::string& ns, const std::vector& v, int flags = 0, const WriteConcern* wc = NULL) = 0; virtual void remove(const std::string& ns, Query query, bool justOne = false, const WriteConcern* wc = NULL) = 0; virtual void remove(const std::string& ns, Query query, int flags, const WriteConcern* wc = NULL) = 0; virtual void update(const std::string& ns, Query query, BSONObj obj, bool upsert = false, bool multi = false, const WriteConcern* wc = NULL) = 0; virtual void update(const std::string& ns, Query query, BSONObj obj, int flags, const WriteConcern* wc = NULL) = 0; virtual ~DBClientInterface() {} /** @return a single object that matches the query. if none do, then the object is empty @throws AssertionException */ virtual BSONObj findOne(const std::string& ns, const Query& query, const BSONObj* fieldsToReturn = 0, int queryOptions = 0); /** query N objects from the database into an array. makes sense mostly when you want a small * number of results. if a huge number, use query() and iterate the cursor. */ void findN(std::vector& out, const std::string& ns, Query query, int nToReturn, int nToSkip = 0, const BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); /** * Saves a document to a collection. * * If 'toSave' already has an '_id' then an update(upsert) operation is performed and * any existing document with that '_id' is overwritten. Otherwise, an insert operation * is performed. * * @param ns The namespace to save the document into. * @param toSave The document to save. * @param wc The write concern for this operation. */ void save(const StringData& ns, const BSONObj& toSave, const WriteConcern* wc = NULL); virtual std::string getServerAddress() const = 0; /** don't use this - called automatically by DBClientCursor for you */ virtual std::auto_ptr getMore(const std::string& ns, long long cursorId, int nToReturn = 0, int options = 0) = 0; }; /** DB "commands" Basically just invocations of connection.$cmd.findOne({...}); */ class MONGO_CLIENT_API DBClientWithCommands : public DBClientInterface { public: /** controls how chatty the client is about network errors & such. See log.h */ logger::LogSeverity _logLevel; DBClientWithCommands() : _logLevel(logger::LogSeverity::Log()), _minWireVersion(0), _maxWireVersion(0), _cachedAvailableOptions((enum QueryOptions)0), _haveCachedAvailableOptions(false) {} /** helper function. run a simple command where the command expression is simply { command : 1 } @param info -- where to put result object. may be null if caller doesn't need that info @param command -- command name @return true if the command returned "ok". */ bool simpleCommand(const std::string& dbname, BSONObj* info, const std::string& command); /** Run a database command. Database commands are represented as BSON objects. Common database commands have prebuilt helper functions -- see below. If a helper is not available you can directly call runCommand. @param dbname database name. Use "admin" for global administrative commands. @param cmd the command object to execute. For example, { ismaster : 1 } @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields set. @param options see enum QueryOptions - normally not needed to run a command @param auth if set, the BSONObj representation will be appended to the command object sent @return true if the command returned "ok". */ virtual bool runCommand(const std::string& dbname, const BSONObj& cmd, BSONObj& info, int options = 0); /** * Authenticate a user. * * The "params" BSONObj should be initialized with some of the fields below. Which fields * are required depends on the mechanism, which is mandatory. * * "mechanism": The string name of the sasl mechanism to use. Mandatory. * "user": The string name of the user to authenticate. Mandatory. * "db": The database target of the auth command, which identifies the location * of the credential information for the user. May be "$external" if * credential information is stored outside of the mongo cluster. Mandatory. * "pwd": The password data. * "digestPassword": Boolean, set to true if the "pwd" is undigested (default). * "serviceName": The GSSAPI service name to use. Defaults to "mongodb". * "serviceHostname": The GSSAPI hostname to use. Defaults to the name of the remote * host. * * Other fields in "params" are silently ignored. * * Returns normally on success, and throws on error. Throws a DBException with getCode() == * ErrorCodes::AuthenticationFailed if authentication is rejected. All other exceptions are * tantamount to authentication failure, but may also indicate more serious problems. */ void auth(const BSONObj& params); /** Authorize access to a particular database. Authentication is separate for each database on the server -- you may authenticate for any number of databases on a single connection. @param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested @param[out] authLevel level of authentication for the given user @return true if successful */ bool auth(const std::string& dbname, const std::string& username, const std::string& pwd, std::string& errmsg, bool digestPassword = true); /** * Logs out the connection for the given database. * * @param dbname the database to logout from. * @param info the result object for the logout command (provided for backwards * compatibility with mongo shell) */ virtual void logout(const std::string& dbname, BSONObj& info); /** count number of objects in collection ns that match the query criteria specified throws UserAssertion if database returns an error */ virtual unsigned long long count(const std::string& ns, const Query& query = Query(), int options = 0, int limit = 0, int skip = 0); static std::string MONGO_CLIENT_FUNC createPasswordDigest(const std::string& username, const std::string& clearTextPassword); /** returns true in isMaster parm if this db is the current master of a replica pair. pass in info for more details e.g.: { "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 } returns true if command invoked successfully. */ virtual bool isMaster(bool& isMaster, BSONObj* info = 0); /** Create a new collection in the database. Normally, collection creation is automatic. You would use this function if you wish to specify special options on creation. If the collection already exists, no action occurs. @param ns fully qualified collection name @param size desired initial extent size for the collection. Must be <= 1000000000 for normal collections. For fixed size (capped) collections, this size is the total/max size of the collection. @param capped if true, this is a fixed size collection (where old data rolls out). @param max maximum number of objects if capped (optional). @return true if successful. */ bool createCollection(const std::string& ns, long long size = 0, bool capped = false, int max = 0, BSONObj* info = 0); /** * Creates a new collection in the database. Allows for a user to provide a BSONObj that * contains extra options. * * @param extraOptions Add extra parameters to the create collection command for features * that are version specific or for which default values have flipped between server * releases. Some examples are "usePowerOf2Sizes" and "autoIndexId". * * @warning Options set in extraOptions which shadow those passed in as parameters will * have indeterminate behavior. * * @see the form of createCollection with less parameters above. * * @see http://docs.mongodb.org/manual/reference/command/create/#dbcmd.create for available * options. */ bool createCollectionWithOptions(const std::string& ns, long long size = 0, bool capped = false, int max = 0, const BSONObj& extraOptions = BSONObj(), BSONObj* info = 0); /** Get error result from the last write operation (insert/update/delete) on this connection. db doesn't change the command's behavior - it is just for auth checks. @return error message text, or empty string if no error. */ std::string getLastError( const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); /** * Same as the form of getLastError that takes a dbname, but just uses the admin DB. */ std::string getLastError(bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); /** Get error result from the last write operation (insert/update/delete) on this connection. db doesn't change the command's behavior - it is just for auth checks. @return full error object. If "w" is -1, wait for propagation to majority of nodes. If "wtimeout" is 0, the operation will block indefinitely if needed. */ virtual BSONObj getLastErrorDetailed( const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); /** * Same as the form of getLastErrorDetailed that takes a dbname, but just uses the admin DB. */ virtual BSONObj getLastErrorDetailed(bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); /** Can be called with the returned value from getLastErrorDetailed to extract an error string. If all you need is the string, just call getLastError() instead. */ static std::string MONGO_CLIENT_FUNC getLastErrorString(const BSONObj& res); /** Return the last error which has occurred, even if not the very last operation. @return { err : , nPrev : , ok : 1 } result.err will be null if no error has occurred. */ BSONObj getPrevError(); /** Reset the previous error state for this connection (accessed via getLastError and getPrevError). Useful when performing several operations at once and then checking for an error after attempting all operations. */ bool resetError() { return simpleCommand("admin", 0, "reseterror"); } /** Delete the specified collection. * @param info An optional output parameter that receives the result object the database * returns from the drop command. May be null if the caller doesn't need that info. */ virtual bool dropCollection(const std::string& ns, BSONObj* info = NULL) { std::string db = nsGetDB(ns); std::string coll = nsGetCollection(ns); uassert(10011, "no collection name", coll.size()); BSONObj temp; if (info == NULL) { info = &temp; } bool res = runCommand(db.c_str(), BSON("drop" << coll), *info); return res; } /** Perform a repair and compaction of the specified database. May take a long time to run. * Disk space must be available equal to the size of the database while repairing. */ bool repairDatabase(const std::string& dbname, BSONObj* info = 0) { return simpleCommand(dbname, info, "repairDatabase"); } /** Copy database from one server or name to another server or name. Generally, you should dropDatabase() first as otherwise the copied information will MERGE into whatever data is already present in this database. For security reasons this function only works when you are authorized to access the "admin" db. However, if you have access to said db, you can copy any database from one place to another. TODO: this needs enhancement to be more flexible in terms of security. This method provides a way to "rename" a database by copying it to a new db name and location. The copy is "repaired" and compacted. fromdb database name from which to copy. todb database name to copy to. fromhost hostname of the database (and optionally, ":port") from which to copy the data. copies from self if "". returns true if successful */ bool copyDatabase(const std::string& fromdb, const std::string& todb, const std::string& fromhost = "", const std::string& mechanism = "DEFAULT", const std::string& username = "", const std::string& password = "", BSONObj* info = 0); /** The Mongo database provides built-in performance profiling capabilities. Uset * setDbProfilingLevel() to enable. Profiling information is then written to the system.profile * collection, which one can then query. */ enum ProfilingLevel { ProfileOff = 0, ProfileSlow = 1, // log very slow (>100ms) operations ProfileAll = 2 }; bool setDbProfilingLevel(const std::string& dbname, ProfilingLevel level, BSONObj* info = 0); bool getDbProfilingLevel(const std::string& dbname, ProfilingLevel& level, BSONObj* info = 0); /** This implicitly converts from char*, string, and BSONObj to be an argument to mapreduce You shouldn't need to explicitly construct this */ struct MROutput { MROutput(const char* collection) : out(BSON("replace" << collection)) {} MROutput(const std::string& collection) : out(BSON("replace" << collection)) {} MROutput(const BSONObj& obj) : out(obj) {} BSONObj out; }; static MROutput MRInline; /** Run a map/reduce job on the server. See http://dochub.mongodb.org/core/mapreduce ns namespace (db+collection name) of input data jsmapf javascript map function code jsreducef javascript reduce function code. query optional query filter for the input output either a string collection name or an object representing output type if not specified uses inline output type returns a result object which contains: { result : , numObjects : , timeMillis : , ok : <1_if_ok>, [, err : ] } For example one might call: result.getField("ok").trueValue() on the result to check if ok. */ BSONObj mapreduce(const std::string& ns, const std::string& jsmapf, const std::string& jsreducef, Query query = Query(), MROutput output = MRInline); /** * Groups documents in a collection by the specified key and performs simple aggregation * functions such as computing counts and sums. * * @note WARNING: Use of the group command is strongly discouraged, it is much better to use * the aggregation framework to acheive similar functionality. * * @see http://docs.mongodb.org/manual/reference/method/db.collection.group * * @param ns The namespace to group * @param key The field or fields to group specified as a projection document: { field: 1 } * @param jsreduce An aggregation function that operates on the documents during the group * ing operation. The function should take two arguments: the current document and an * aggregation result for that group. * @param output The output vector. * @param initial Initial aggregation result document. * @param query Optional selection criteria to determine which documents to process. * @param finalize Optional function that runs for each item in the result set before * returning the final values in the output vector. */ void group(const StringData& ns, const StringData& jsreduce, std::vector* output, const BSONObj& initial = BSONObj(), const Query& query = Query(), const BSONObj& key = BSONObj(), const StringData& finalize = ""); /** * Does the same thing as 'group' but accepts a key function, 'jskey', that is used to * create an object representing the key. This allows for grouping on calculated fields * rather on existing fields alone. * * @see DBClientWithCommands::group */ void groupWithKeyFunction(const StringData& ns, const StringData& jsreduce, std::vector* output, const BSONObj& initial = BSONObj(), const Query& query = Query(), const StringData& jskey = "", const StringData& finalize = ""); /** * Finds the distinct values for a specified field across a single collection and returns * the results in an array. * * @param ns The namespace to query for distinct values. * @param field The field for which to return distinct values. * Examples: "name", "address.street" * @param query Optional query that specifies a filter for documents from which to retrieve * distinct values. */ BSONObj distinct(const StringData& ns, const StringData& field, const Query& query = Query()); /** Run javascript code on the database server. dbname database SavedContext in which the code runs. The javascript variable 'db' will be assigned to this database when the function is invoked. jscode source code for a javascript function. info the command object which contains any information on the invocation result including the return value and other information. If an error occurs running the jscode, error information will be in info. (try "log() << info.toString()") retValue return value from the jscode function. args args to pass to the jscode function. when invoked, the 'args' variable will be defined for use by the jscode. nolock if true, the server will not take a global write lock when executing the jscode. returns true if runs ok. See testDbEval() in dbclient.cpp for an example of usage. */ MONGO_CLIENT_DEPRECATED("deprecated in MongoDB 3.0") bool eval(const std::string& dbname, const std::string& jscode, BSONObj& info, BSONElement& retValue, BSONObj* args = 0, bool nolock = false) { return evalDeprecated(dbname, jscode, info, retValue, args, nolock); } bool evalDeprecated(const std::string& dbname, const std::string& jscode, BSONObj& info, BSONElement& retValue, BSONObj* args = 0, bool nolock = false); /** validate a collection, checking for errors and reporting back statistics. this operation is slow and blocking. */ bool validate(const std::string& ns, bool scandata = true) { BSONObj cmd = BSON("validate" << nsGetCollection(ns) << "scandata" << scandata); BSONObj info; return runCommand(nsGetDB(ns).c_str(), cmd, info); } /* The following helpers are simply more convenient forms of eval() for certain common cases */ /* invocation with no return value of interest -- with or without one simple parameter */ MONGO_CLIENT_DEPRECATED("deprecated in MongoDB 3.0") bool eval(const std::string& dbname, const std::string& jscode) { return evalDeprecated(dbname, jscode); } bool evalDeprecated(const std::string& dbname, const std::string& jscode); template MONGO_CLIENT_DEPRECATED("deprecated in MongoDB 3.0") bool eval(const std::string& dbname, const std::string& jscode, T parm1) { return evalDeprecated(dbname, jscode, parm1); } template bool evalDeprecated(const std::string& dbname, const std::string& jscode, T parm1) { BSONObj info; BSONElement retValue; BSONObjBuilder b; b.append("0", parm1); BSONObj args = b.done(); return eval(dbname, jscode, info, retValue, &args); } /** eval invocation with one parm to server and one numeric field (either int or double) * returned */ template MONGO_CLIENT_DEPRECATED("deprecated in MongoDB 3.0") bool eval(const std::string& dbname, const std::string& jscode, T parm1, NumType& ret) { return evalDeprecated(dbname, jscode, parm1, ret); } template bool evalDeprecated(const std::string& dbname, const std::string& jscode, T parm1, NumType& ret) { BSONObj info; BSONElement retValue; BSONObjBuilder b; b.append("0", parm1); BSONObj args = b.done(); if (!eval(dbname, jscode, info, retValue, &args)) return false; ret = (NumType)retValue.number(); return true; } /** get a list of all the current databases uses the { listDatabases : 1 } command. throws on error */ std::list getDatabaseNames(); /** * Get a list of all the current collections in db. */ std::list getCollectionNames(const std::string& db, const BSONObj& filter = BSONObj()); /** * { name : "", * options : { } * } */ std::list getCollectionInfos(const std::string& db, const BSONObj& filter = BSONObj()); /** * Returns a DBClientCursor with collection information objects. * * Example collection information object: * { * "name" : "mongo_cxx_driver", * "options" : { * "flags" : 1 * } * } */ std::auto_ptr enumerateCollections(const std::string& db, const BSONObj& filter = BSONObj(), int batchSize = 0); bool exists(const std::string& ns); /** Create an index on the collection 'ns' as described by the given keys. If you wish * to specify options, see the more flexible overload of 'createIndex' which takes an * IndexSpec object. Failure to construct the index is reported by throwing an * OperationException. * * @param ns Namespace on which to create the index * @param keys Document describing keys and index types. You must provide at least one * field and its direction. */ void createIndex(const StringData& ns, const BSONObj& keys) { return createIndex(ns, IndexSpec().addKeys(keys)); } /** Create an index on the collection 'ns' as described by the given * descriptor. Failure to construct the index is reported by throwing an * OperationException. * * @param ns Namespace on which to create the index * @param descriptor Configuration object describing the index to create. The * descriptor must describe at least one key and index type. */ virtual void createIndex(const StringData& ns, const IndexSpec& descriptor); virtual std::list getIndexSpecs(const std::string& ns, int options = 0); /** * Enumerates all indexes on ns (a db-qualified collection name). Returns a list of the index * names. */ virtual std::list getIndexNames(const std::string& ns, int options = 0); virtual std::auto_ptr enumerateIndexes(const std::string& ns, int options = 0, int batchSize = 0); virtual void dropIndex(const std::string& ns, BSONObj keys); virtual void dropIndex(const std::string& ns, const std::string& indexName); /** drops all indexes for the collection */ virtual void dropIndexes(const std::string& ns); virtual void reIndex(const std::string& ns); static std::string genIndexName(const BSONObj& keys); /** Erase / drop an entire database */ virtual bool dropDatabase(const std::string& dbname, BSONObj* info = 0) { bool ret = simpleCommand(dbname, info, "dropDatabase"); return ret; } virtual std::string toString() const = 0; /** * A function type for runCommand hooking; the function takes a pointer * to a BSONObjBuilder and returns nothing. The builder contains a * runCommand BSON object. * Once such a function is set as the runCommand hook, every time the DBClient * processes a runCommand, the hook will be called just prior to sending it to the server. */ typedef stdx::function RunCommandHookFunc; virtual void setRunCommandHook(RunCommandHookFunc func); RunCommandHookFunc getRunCommandHook() const { return _runCommandHook; } /** * Similar to above, but for running a function on a command response after a command * has been run. */ typedef stdx::function PostRunCommandHookFunc; virtual void setPostRunCommandHook(PostRunCommandHookFunc func); PostRunCommandHookFunc getPostRunCommandHook() const { return _postRunCommandHook; } protected: /** if the result of a command is ok*/ bool isOk(const BSONObj&); /** if the element contains a not master error */ bool isNotMasterErrorString(const BSONElement& e); BSONObj _countCmd(const std::string& ns, const Query& query, int options, int limit, int skip); /** * Look up the options available on this client. Caches the answer from * _lookupAvailableOptions(), below. */ QueryOptions availableOptions(); virtual QueryOptions _lookupAvailableOptions(); virtual void _auth(const BSONObj& params); /** * Use the MONGODB-CR protocol to authenticate as "username" against the database "dbname", * with the given password. If digestPassword is false, the password is assumed to be * pre-digested. Returns false on failure, and sets "errmsg". */ bool _authMongoCR(const std::string& dbname, const std::string& username, const std::string& pwd, BSONObj* info, bool digestPassword); /** * Use the MONGODB-X509 protocol to authenticate as "username. The certificate details * has already been communicated automatically as part of the connect call. * Returns false on failure and set "errmsg". */ bool _authX509(const std::string& dbname, const std::string& username, BSONObj* info); /** * These functions will be executed by the driver on runCommand calls. */ RunCommandHookFunc _runCommandHook; PostRunCommandHookFunc _postRunCommandHook; int _minWireVersion; int _maxWireVersion; private: enum QueryOptions _cachedAvailableOptions; bool _haveCachedAvailableOptions; void _buildGroupObj(const StringData& ns, const StringData& jsreduce, const BSONObj& initial, const Query& query, const StringData& finalize, BSONObjBuilder* groupObj); void _runGroup(const StringData& ns, const BSONObj& group, const Query& query, std::vector* output); std::auto_ptr _legacyCollectionInfo(const std::string& db, const BSONObj& filter, int batchSize); }; class DBClientWriter; class WriteOperation; /** abstract class that implements the core db operations */ class MONGO_CLIENT_API DBClientBase : public DBClientWithCommands, public DBConnector { friend class BulkOperationBuilder; protected: static AtomicInt64 ConnectionIdSequence; long long _connectionId; // unique connection id for this connection const boost::scoped_ptr _wireProtocolWriter; const boost::scoped_ptr _commandWriter; WriteConcern _writeConcern; int _maxBsonObjectSize; int _maxMessageSizeBytes; int _maxWriteBatchSize; void _write(const std::string& ns, const std::vector& writes, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult); public: static const uint64_t INVALID_SOCK_CREATION_TIME; DBClientBase(); // Required because compiler can't generate a destructor for the _writer // as it is an incomplete type. virtual ~DBClientBase(); long long getConnectionId() const { return _connectionId; } const WriteConcern& getWriteConcern() const { return _writeConcern; } void setWriteConcern(const WriteConcern& w) { _writeConcern = w; } void setWireVersions(int minWireVersion, int maxWireVersion) { _minWireVersion = minWireVersion; _maxWireVersion = maxWireVersion; } virtual int getMinWireVersion() { return _minWireVersion; } virtual int getMaxWireVersion() { return _maxWireVersion; } int getMaxBsonObjectSize() { return _maxBsonObjectSize; } int getMaxMessageSizeBytes() { return _maxMessageSizeBytes; } int getMaxWriteBatchSize() { return _maxWriteBatchSize; } /** send a query to the database. @param ns namespace to query, format is .[.]* @param query query to perform on the collection. this is a BSONObj (binary JSON) You may format as { query: { ... }, orderby: { ... } } to specify a sort order. @param nToReturn n to return (i.e., limit). 0 = unlimited @param nToSkip start with the nth item @param fieldsToReturn optional template of which fields to select. if unspecified, returns all fields @param queryOptions see options enum at top of this file @return cursor. 0 if error (connection failure) @throws AssertionException */ virtual std::auto_ptr query(const std::string& ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); /** * Returns a list of up to 'numCursors' cursors that can be iterated concurrently. * * As long as the collection is not modified during scanning, each document appears once * in one of the cursors' result sets. * * @note Warning: One must delete the cursors after use. * @note Warning: One must delete any new connections created by the connection factory * after use. * * @see example usage in dbclient_test.cpp -> DBClientTest/ParallelCollectionScan * * @param ns The namespace to scan * @param numCursors Number of cursors to return. You may get back less than you asked for. * @param cursors Output vector to hold cursors created for this scan. * @param connectionFactory Function that returns a pointer to a DBClientBase for use by * newly created cursors. The function takes zero parameters but additional parameters * may be bound (if required) using std::bind. See the example listed above for more info. */ virtual void parallelScan(const StringData& ns, int numCursors, std::vector* cursors, stdx::function connectionFactory); virtual std::auto_ptr aggregate(const std::string& ns, const BSONObj& pipeline, const BSONObj* aggregateOptions = NULL, int queryOptions = 0); /** Uses QueryOption_Exhaust, when available. Exhaust mode sends back all data queries as fast as possible, with no back-and-forth for OP_GETMORE. If you are certain you will exhaust the query, it could be useful. Use the DBClientCursorBatchIterator version, below, if you want to do items in large blocks, perhaps to avoid granular locking and such. */ virtual unsigned long long query(stdx::function f, const std::string& ns, Query query, const BSONObj* fieldsToReturn = 0, int queryOptions = 0); virtual unsigned long long query(stdx::function f, const std::string& ns, Query query, const BSONObj* fieldsToReturn = 0, int queryOptions = 0); /** don't use this - called automatically by DBClientCursor for you @param cursorId id of cursor to retrieve @return an handle to a previously allocated cursor @throws AssertionException */ virtual std::auto_ptr getMore(const std::string& ns, long long cursorId, int nToReturn = 0, int options = 0); /** insert an object into the database */ virtual void insert(const std::string& ns, BSONObj obj, int flags = 0, const WriteConcern* wc = NULL); /** insert a vector of objects into the database */ virtual void insert(const std::string& ns, const std::vector& v, int flags = 0, const WriteConcern* wc = NULL); /** updates objects matching query */ virtual void update(const std::string& ns, Query query, BSONObj obj, bool upsert = false, bool multi = false, const WriteConcern* wc = NULL); virtual void update( const std::string& ns, Query query, BSONObj obj, int flags, const WriteConcern* wc = NULL); /** * Modifies and returns a single document. * * @note By default, the returned document does not include modifications made on update. * * @param ns Namespace on which to perform this findAndModify. * @param update Update document to be applied. * @param query Filter for the update. * @param upsert Insert if object does not exist. * @param sort Sort for the filter. * @param new Return the updated rather than original object. * @param fields Fields to return. Specifies inclusion with 1, "{: 1, ...}" * @param wc The write concern for this operation. */ BSONObj findAndModify(const StringData& ns, const BSONObj& query, const BSONObj& update, bool upsert = false, bool returnNew = false, const BSONObj& sort = BSONObj(), const BSONObj& fields = BSONObj(), const WriteConcern* wc = NULL, bool bypassDocumentValidation = false); /** * Removes and returns a single document. * * @note By default, the returned document does not include modifications made on update. * * @param ns Namespace on which to perform this findAndModify. * @param query Filter for the update. * @param sort Sort for the filter. * @param fields Fields to return. Specifies inclusion with 1, "{: 1, ...}" * @param wc The write concern for this operation. */ BSONObj findAndRemove(const StringData& ns, const BSONObj& query, const BSONObj& sort = BSONObj(), const BSONObj& fields = BSONObj(), const WriteConcern* wc = NULL); /** * Initializes an unordered bulk operation by returning an object that can be * used to enqueue multiple operations for batch execution. * * @param ns Namespace on which to apply the operations. * @see BulkOperationBuilder */ virtual BulkOperationBuilder initializeUnorderedBulkOp(const std::string& ns); /** * Initializes an ordered bulk operation by returning an object that can be * used to enqueue multiple operations for batch execution. * * @param ns Namespace on which to apply the operations. * @see BulkOperationBuilder */ virtual BulkOperationBuilder initializeOrderedBulkOp(const std::string& ns); /** remove matching objects from the database @param justOne if this true, then once a single match is found will stop */ virtual void remove(const std::string& ns, Query q, bool justOne = 0, const WriteConcern* wc = NULL); virtual void remove(const std::string& ns, Query query, int flags, const WriteConcern* wc = NULL); virtual bool isFailed() const = 0; /** * if not checked recently, checks whether the underlying socket/sockets are still valid */ virtual bool isStillConnected() = 0; virtual void killCursor(long long cursorID) = 0; virtual bool callRead(Message& toSend, Message& response) = 0; // virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if // needed virtual ConnectionString::ConnectionType type() const = 0; virtual double getSoTimeout() const = 0; virtual uint64_t getSockCreationMicroSec() const { return INVALID_SOCK_CREATION_TIME; } virtual void reset() {} private: void _findAndModify(const StringData& ns, const BSONObj& query, const BSONObj& update, const BSONObj& sort, bool returnNew, bool upsert, const BSONObj& fields, const WriteConcern* wc, bool bypassDocumentValidation, BSONObjBuilder* out); }; // DBClientBase class DBClientReplicaSet; class MONGO_CLIENT_API ConnectException : public UserException { public: ConnectException(std::string msg) : UserException(9000, msg) {} }; /** A basic connection to the database. This is the main entry point for talking to a simple Mongo setup */ class MONGO_CLIENT_API DBClientConnection : public DBClientBase { public: using DBClientBase::query; /** @param _autoReconnect if true, automatically reconnect on a connection failure @param cp - ignored: do not provide a value for this paramter @param timeout tcp timeout in seconds - this is for read/write, not connect. Connect timeout is fixed, but short, at 5 seconds. */ DBClientConnection(bool _autoReconnect = false, DBClientReplicaSet* cp = 0, double so_timeout = 0); virtual ~DBClientConnection() { _numConnections.fetchAndAdd(-1); } /** Connect to a Mongo database server. If autoReconnect is true, you can try to use the DBClientConnection even when false was returned -- it will try to connect again. @param server server to connect to. @param errmsg any relevant error message will appended to the string @return false if fails to connect. */ virtual bool connect(const HostAndPort& server, std::string& errmsg); /** Compatibility connect now that HostAndPort has an explicit constructor */ bool connect(const std::string& server, std::string& errmsg) { return connect(HostAndPort(server), errmsg); } /** Connect to a Mongo database server. Exception throwing version. Throws a UserException if cannot connect. If autoReconnect is true, you can try to use the DBClientConnection even when false was returned -- it will try to connect again. @param serverHostname host to connect to. can include port number ( 127.0.0.1 , 127.0.0.1:5555 ) */ void connect(const std::string& serverHostname) { std::string errmsg; if (!connect(HostAndPort(serverHostname), errmsg)) throw ConnectException(std::string("can't connect ") + errmsg); } /** * Logs out the connection for the given database. * * @param dbname the database to logout from. * @param info the result object for the logout command (provided for backwards * compatibility with mongo shell) */ virtual void logout(const std::string& dbname, BSONObj& info); virtual std::auto_ptr query(const std::string& ns, Query query = Query(), int nToReturn = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); virtual unsigned long long query(stdx::function f, const std::string& ns, Query query, const BSONObj* fieldsToReturn, int queryOptions); virtual bool runCommand(const std::string& dbname, const BSONObj& cmd, BSONObj& info, int options = 0); /** @return true if this connection is currently in a failed state. When autoreconnect is on, a connection will transition back to an ok state after reconnecting. */ bool isFailed() const { return _failed; } bool isStillConnected() { return p ? p->isStillConnected() : true; } MessagingPort& port() { verify(p); return *p; } std::string toString() const { std::stringstream ss; ss << _serverString; if (!_serverAddrString.empty()) ss << " (" << _serverAddrString << ")"; if (_failed) ss << " failed"; return ss.str(); } std::string getServerAddress() const { return _serverString; } const HostAndPort& getServerHostAndPort() const { return _server; } virtual void killCursor(long long cursorID); virtual bool callRead(Message& toSend, Message& response) { return call(toSend, response); } virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0); virtual bool recv(Message& m); virtual void checkResponse(const char* data, int nReturned, bool* retry = NULL, std::string* host = NULL); virtual bool call(Message& toSend, Message& response, bool assertOk = true, std::string* actualServer = 0); virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; } void setSoTimeout(double timeout); double getSoTimeout() const { return _so_timeout; } virtual bool lazySupported() const { return true; } static int MONGO_CLIENT_FUNC getNumConnections() { return _numConnections.load(); } /** * Set the name of the replica set that this connection is associated to. * Note: There is no validation on replSetName. */ void setParentReplSetName(const std::string& replSetName); static void MONGO_CLIENT_FUNC setLazyKillCursor(bool lazy) { _lazyKillCursor = lazy; } static bool MONGO_CLIENT_FUNC getLazyKillCursor() { return _lazyKillCursor; } uint64_t getSockCreationMicroSec() const; protected: virtual void _auth(const BSONObj& params); virtual void sayPiggyBack(Message& toSend); boost::scoped_ptr p; boost::scoped_ptr server; bool _failed; const bool autoReconnect; Backoff autoReconnectBackoff; HostAndPort _server; // remember for reconnects std::string _serverString; // server host and port std::string _serverAddrString; // resolved ip of server void _checkConnection(); // throws SocketException if in failed state and not reconnecting or if waiting to reconnect void checkConnection() { if (_failed) _checkConnection(); } std::map authCache; double _so_timeout; bool _connect(std::string& errmsg); static AtomicInt32 _numConnections; static bool _lazyKillCursor; // lazy means we piggy back kill cursors on next op #ifdef MONGO_SSL SSLManagerInterface* sslManager(); #endif private: /** * Checks the BSONElement for the 'not master' keyword and if it does exist, * try to inform the replica set monitor that the host this connects to is * no longer primary. */ void handleNotMasterResponse(const BSONElement& elemToCheck); // Contains the string for the replica set name of the host this is connected to. // Should be empty if this connection is not pointing to a replica set member. std::string _parentReplSetName; }; /** pings server to check if it's up */ MONGO_CLIENT_API bool MONGO_CLIENT_FUNC serverAlive(const std::string& uri); MONGO_CLIENT_API BSONElement MONGO_CLIENT_FUNC getErrField(const BSONObj& result); MONGO_CLIENT_API bool MONGO_CLIENT_FUNC hasErrField(const BSONObj& result); MONGO_CLIENT_API inline std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& s, const Query& q) { return s << q.toString(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/dbclientmockcursor.h000066400000000000000000000024011273231111400254060ustar00rootroot00000000000000//@file dbclientmockcursor.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclientcursor.h" #include "mongo/client/export_macros.h" namespace mongo { class DBClientMockCursor : public DBClientCursorInterface { public: DBClientMockCursor(const BSONArray& mockCollection) : _iter(mockCollection) {} virtual ~DBClientMockCursor() {} bool more() { return _iter.more(); } BSONObj next() { return _iter.next().Obj(); } private: BSONObjIterator _iter; // non-copyable , non-assignable DBClientMockCursor(const DBClientMockCursor&); DBClientMockCursor& operator=(const DBClientMockCursor&); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/delete_write_operation.cpp000066400000000000000000000043411273231111400266060ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/delete_write_operation.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/write_options.h" #include "mongo/db/namespace_string.h" namespace mongo { namespace { const char kCommandKey[] = "delete"; const char kBatchName[] = "deletes"; const char kSelectorKey[] = "q"; const char kLimitKey[] = "limit"; } // namespace DeleteWriteOperation::DeleteWriteOperation(const BSONObj& selector, int flags) : _selector(selector), _flags(flags) {} WriteOpType DeleteWriteOperation::operationType() const { return dbWriteDelete; } int DeleteWriteOperation::incrementalSize() const { return _selector.objsize(); } const char* DeleteWriteOperation::batchName() const { return kBatchName; } void DeleteWriteOperation::startRequest(const std::string& ns, bool, BufBuilder* builder) const { builder->appendNum(0); builder->appendStr(ns); builder->appendNum(_flags); } void DeleteWriteOperation::appendSelfToRequest(BufBuilder* builder) const { _selector.appendSelfToBufBuilder(*builder); } void DeleteWriteOperation::startCommand(const std::string& ns, BSONObjBuilder* command) const { command->append(kCommandKey, nsToCollectionSubstring(ns)); } void DeleteWriteOperation::appendSelfToCommand(BSONArrayBuilder* batch) const { BSONObjBuilder updateBuilder; appendSelfToBSONObj(&updateBuilder); batch->append(updateBuilder.obj()); } void DeleteWriteOperation::appendSelfToBSONObj(BSONObjBuilder* obj) const { obj->append(kSelectorKey, _selector); obj->append(kLimitKey, _flags & RemoveOption_JustOne); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/delete_write_operation.h000066400000000000000000000026211273231111400262520ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/write_operation_base.h" namespace mongo { class DeleteWriteOperation : public WriteOperationBase { public: DeleteWriteOperation(const BSONObj& selector, int flags); virtual WriteOpType operationType() const; virtual const char* batchName() const; virtual int incrementalSize() const; virtual void startRequest(const std::string& ns, bool ordered, BufBuilder* builder) const; virtual void appendSelfToRequest(BufBuilder* builder) const; virtual void startCommand(const std::string& ns, BSONObjBuilder* command) const; virtual void appendSelfToCommand(BSONArrayBuilder* request) const; virtual void appendSelfToBSONObj(BSONObjBuilder* obj) const; private: const BSONObj _selector; int _flags; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/000077500000000000000000000000001273231111400231625ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/aggregation.cpp000066400000000000000000000057461273231111400261710ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include #include #include #include "mongo/client/dbclient.h" using namespace mongo; int main(int argc, char* argv[]) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { std::cout << "couldn't connect : " << errmsg << std::endl; return EXIT_FAILURE; } conn->dropCollection("test.test"); // Don't run on MongoDB < 2.2 BSONObj cmdResult; conn->runCommand("admin", BSON("buildinfo" << true), cmdResult); std::vector versionArray = cmdResult["versionArray"].Array(); if (versionArray[0].Int() < 2 || versionArray[1].Int() < 2) return EXIT_SUCCESS; conn->insert("test.test", BSON("x" << 0)); conn->insert("test.test", BSON("x" << 1)); conn->insert("test.test", BSON("x" << 1)); conn->insert("test.test", BSON("x" << 2)); conn->insert("test.test", BSON("x" << 2)); conn->insert("test.test", BSON("x" << 2)); std::auto_ptr cursor = conn->aggregate("test.test", BSON_ARRAY(BSON("$match" << BSON("x" << GT << 0)) << BSON("$group" << BSON("_id" << "$x" << "count" << BSON("$sum" << 1))))); std::cout << "------- AGGREGATION -------" << std::endl; while (cursor->more()) { std::cout << cursor->next() << std::endl; } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/arrayExample.cpp000066400000000000000000000063071273231111400263260ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include #include using mongo::BSONArray; using mongo::BSONArrayBuilder; using mongo::BSONObj; using mongo::BSONObjBuilder; using mongo::BSONElement; using std::cout; using std::endl; using std::list; using std::vector; int main() { mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << endl; return EXIT_FAILURE; } // Build an object BSONObjBuilder bob; // Build an array BSONArrayBuilder bab; bab.append("first"); bab.append("second"); bab.append("third"); bab.append("fourth").append("fifth"); // Place array in object at key "x" bob.appendArray("x", bab.arr()); // Use BSON_ARRAY macro like BSON macro, but without keys BSONArray arr = BSON_ARRAY("hello" << 1 << BSON("foo" << BSON_ARRAY("bar" << "baz" << "qux"))); // Place the second array in object at key "y" bob.appendArray("y", arr); // Create the object BSONObj an_obj = bob.obj(); /* * Extract the array directly from the BSONObj. * * Transforms a BSON array into a vector of BSONElements. * * We match array # positions with their vector position, and ignore * any fields with non-numeric field names. */ vector elements = an_obj["x"].Array(); // Print the array out cout << "Our Array:" << endl; for (vector::iterator it = elements.begin(); it != elements.end(); ++it) { cout << *it << endl; } cout << endl; // Extract the array as a BSONObj BSONObj myarray = an_obj["y"].Obj(); // Convert it to a vector vector v; myarray.elems(v); // Convert it to a list list L; myarray.elems(L); // Print the vector out cout << "The Vector Version:" << endl; for (vector::iterator it = v.begin(); it != v.end(); ++it) { cout << *it << endl; } cout << endl; // Print the list out cout << "The List Version:" << endl; for (list::iterator it = L.begin(); it != L.end(); ++it) { cout << *it << endl; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/authTest.cpp000066400000000000000000000101101273231111400254600ustar00rootroot00000000000000// authTest.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include #include #include #include using namespace mongo; bool serverLTE(DBClientBase* c, int major, int minor) { BSONObj result; c->runCommand("admin", BSON("buildinfo" << true), result); std::vector version = result.getField("versionArray").Array(); int serverMajor = version[0].Int(); int serverMinor = version[1].Int(); // std::pair uses lexicographic ordering return std::make_pair(serverMajor, serverMinor) <= std::make_pair(major, minor); } int main(int argc, const char** argv) { using std::cout; using std::endl; using std::string; if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } client::Options autoTimeoutOpts = client::Options(); autoTimeoutOpts.setAutoShutdownGracePeriodMillis(250); mongo::client::GlobalInstance instance(autoTimeoutOpts); if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect: " << errmsg << endl; return EXIT_FAILURE; } bool worked; BSONObj ret; // clean up old data from any previous tests worked = conn->runCommand("test", BSON("dropAllUsersFromDatabase" << 1), ret); if (!worked) { cout << "Running MongoDB < 2.5.3 so falling back to old remove" << endl; conn->remove("test.system.users", BSONObj()); } // create a new user worked = conn->runCommand("test", BSON("createUser" << "eliot" << "pwd" << "bar" << "roles" << BSON_ARRAY("readWrite")), ret); if (!worked) { cout << "Running MongoDB < 2.5.3 so falling back to old user creation" << endl; conn->insert("test.system.users", BSON("user" << "eliot" << "pwd" << conn->createPasswordDigest("eliot", "bar"))); } errmsg.clear(); if (!conn->auth("test", "eliot", "bar", errmsg)) { cout << "Authentication failed, when it should have succeeded. Got error: " << errmsg << endl; return EXIT_FAILURE; } try { if (conn->auth("test", "eliot", "bars", errmsg)) { // incorrect password cout << "Authentication with invalid password should have failed but didn't" << endl; return EXIT_FAILURE; } } catch (const DBException&) { // Expected on v2.2 and below assert(serverLTE(conn.get(), 2, 2)); } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/clientTest.cpp000066400000000000000000000253641273231111400260160ustar00rootroot00000000000000// clientTest.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * a simple test for the c++ driver */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif // this header should be first to ensure that it includes cleanly in any context #include "mongo/client/dbclient.h" #include #include #ifndef verify #define verify(x) MONGO_verify(x) #endif using namespace std; using namespace mongo; int main(int argc, const char** argv) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); const char* ns = "test.test1"; conn->dropCollection(ns); // clean up old data from any previous tests conn->remove(ns, BSONObj()); verify(conn->findOne(ns, BSONObj()).isEmpty()); // test insert conn->insert(ns, BSON("name" << "eliot" << "num" << 1)); verify(!conn->findOne(ns, BSONObj()).isEmpty()); // test remove conn->remove(ns, BSONObj()); verify(conn->findOne(ns, BSONObj()).isEmpty()); // insert, findOne testing conn->insert(ns, BSON("name" << "eliot" << "num" << 1)); { BSONObj res = conn->findOne(ns, BSONObj()); verify(strstr(res.getStringField("name"), "eliot")); verify(!strstr(res.getStringField("name2"), "eliot")); verify(1 == res.getIntField("num")); } // cursor conn->insert(ns, BSON("name" << "sara" << "num" << 2)); { auto_ptr cursor = conn->query(ns, BSONObj()); int count = 0; while (cursor->more()) { count++; BSONObj obj = cursor->next(); } verify(count == 2); } { auto_ptr cursor = conn->query(ns, BSON("num" << 1)); int count = 0; while (cursor->more()) { count++; BSONObj obj = cursor->next(); } verify(count == 1); } { auto_ptr cursor = conn->query(ns, BSON("num" << 3)); int count = 0; while (cursor->more()) { count++; BSONObj obj = cursor->next(); } verify(count == 0); } // update { BSONObj res = conn->findOne(ns, BSONObjBuilder().append("name", "eliot").obj()); verify(!strstr(res.getStringField("name2"), "eliot")); BSONObj after = BSONObjBuilder().appendElements(res).append("name2", "h").obj(); conn->update(ns, BSONObjBuilder().append("name", "eliot2").obj(), after); res = conn->findOne(ns, BSONObjBuilder().append("name", "eliot").obj()); verify(!strstr(res.getStringField("name2"), "eliot")); verify(conn->findOne(ns, BSONObjBuilder().append("name", "eliot2").obj()).isEmpty()); conn->update(ns, BSONObjBuilder().append("name", "eliot").obj(), after); res = conn->findOne(ns, BSONObjBuilder().append("name", "eliot").obj()); verify(strstr(res.getStringField("name"), "eliot")); verify(strstr(res.getStringField("name2"), "h")); verify(conn->findOne(ns, BSONObjBuilder().append("name", "eliot2").obj()).isEmpty()); // upsert try { conn->update( ns, BSONObjBuilder().append("name", "eliot2").obj(), after, UpdateOption_Upsert); } catch (OperationException&) { // This upsert throws an OperationException because of a duplicate key error: // The upserted document has the same _id as one already in the collection } verify(!conn->findOne(ns, BSONObjBuilder().append("name", "eliot").obj()).isEmpty()); } // Create an index on 'name' conn->createIndex(ns, BSON("name" << 1)); /* { // 5 second TTL index const char * ttlns = "test.ttltest1"; conn->dropCollection( ttlns ); { mongo::BSONObjBuilder b; b.appendTimeT("ttltime", time(0)); b.append("name", "foo"); conn->insert(ttlns, b.obj()); } conn->ensureIndex(ttlns, BSON("ttltime" << 1), false, "", true, false, -1, 5); verify(!conn->findOne(ttlns, BSONObjBuilder().append("name", "foo").obj()).isEmpty()); // Sleep 66 seconds, 60 seconds for the TTL loop, 5 seconds for the TTL and 1 to ensure sleepsecs(66); verify(conn->findOne(ttlns, BSONObjBuilder().append("name", "foo").obj()).isEmpty()); } */ { // hint related tests verify(conn->findOne(ns, "{ name : 'eliot' }")["name"].str() == "eliot"); verify(conn->getLastError() == ""); // nonexistent index test bool asserted = false; try { conn->findOne(ns, Query("{name:\"eliot\"}").hint("foo_1}")); } catch (...) { asserted = true; } verify(asserted); // existing index verify(conn->findOne(ns, Query("{name:'eliot'}").hint("name_1")).hasElement("name")); // run validate verify(conn->validate(ns)); } { // timestamp test const char* tsns = "test.tstest1"; conn->dropCollection(tsns); { mongo::BSONObjBuilder b; b.appendTimestamp("ts", Timestamp_t()); conn->insert(tsns, b.obj()); } mongo::BSONObj out = conn->findOne(tsns, mongo::BSONObj()); uint32_t oldTime = out["ts"].timestamp().seconds(); uint32_t oldInc = out["ts"].timestamp().increment(); { mongo::BSONObjBuilder b1; b1.append(out["_id"]); mongo::BSONObjBuilder b2; b2.append(out["_id"]); b2.appendTimestamp("ts", Timestamp_t()); conn->update(tsns, b1.obj(), b2.obj()); } BSONObj found = conn->findOne(tsns, mongo::BSONObj()); cout << "old: " << out << "\nnew: " << found << endl; verify((oldTime < found["ts"].timestamp().seconds()) || (oldTime == found["ts"].timestamp().seconds() && oldInc < found["ts"].timestamp().increment())); } { // check that killcursors doesn't affect last error verify(conn->getLastError().empty()); BufBuilder b; b.appendNum((int)0); // reserved b.appendNum((int)-1); // invalid # of cursors triggers exception b.appendNum((int)-1); // bogus cursor id Message m; m.setData(dbKillCursors, b.buf(), b.len()); // say() is protected in DBClientConnection, so get superclass static_cast(conn.get())->say(m); verify(conn->getLastError().empty()); } { list l = conn->getDatabaseNames(); for (list::iterator i = l.begin(); i != l.end(); i++) { cout << "db name : " << *i << endl; } l = conn->getCollectionNames("test"); for (list::iterator i = l.begin(); i != l.end(); i++) { cout << "coll name : " << *i << endl; } } { const string ns = "test.listMyIndexes"; conn->dropCollection(ns); conn->insert(ns, BSON("a" << 1)); conn->createIndex(ns, BSON("a" << 1)); conn->createIndex(ns, BSON("b" << 1)); conn->createIndex(ns, BSON("c" << 1)); list indexNames(conn->getIndexNames(ns)); std::multiset names(indexNames.begin(), indexNames.end()); verify(indexNames.size() == 4); verify(names.count(string("_id_")) == 1); verify(names.count(string("a_1")) == 1); verify(names.count(string("b_1")) == 1); verify(names.count(string("c_1")) == 1); } { // Map Reduce (this mostly just tests that it compiles with all output types) const string ns = "test.mr"; conn->insert(ns, BSON("a" << 1)); conn->insert(ns, BSON("a" << 1)); const char* map = "function() { emit(this.a, 1); }"; const char* reduce = "function(key, values) { return Array.sum(values); }"; const string outcoll = ns + ".out"; BSONObj out; out = conn->mapreduce(ns, map, reduce, BSONObj()); // default to inline // MONGO_PRINT(out); out = conn->mapreduce(ns, map, reduce, BSONObj(), outcoll); // MONGO_PRINT(out); out = conn->mapreduce(ns, map, reduce, BSONObj(), outcoll.c_str()); // MONGO_PRINT(out); out = conn->mapreduce(ns, map, reduce, BSONObj(), BSON("reduce" << outcoll)); // MONGO_PRINT(out); } { // test timeouts boost::scoped_ptr conn(cs.connect(errmsg, 2)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; throw - 11; } conn->insert("test.totest", BSON("x" << 1)); BSONObj res; bool gotError = false; verify(conn->evalDeprecated("test", "return db.totest.findOne().x", res)); try { conn->evalDeprecated("test", "sleep(5000); return db.totest.findOne().x", res); } catch (std::exception& e) { gotError = true; std::cout << e.what() << endl; } verify(gotError); // sleep so the server isn't locked anymore sleepsecs(4); verify(conn->evalDeprecated("test", "return db.totest.findOne().x", res)); } cout << "client test finished!" << endl; return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/connect.cpp000066400000000000000000000074561273231111400253330ustar00rootroot00000000000000// clientTest.cpp /* Copyright 2016 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include #include // this header should be first to ensure that it includes cleanly in any context #include "mongo/client/dbclient.h" #include "mongo/stdx/functional.h" namespace { class OstreamAppender : public mongo::logger::MessageLogDomain::EventAppender { public: explicit OstreamAppender(std::ostream& stream) : _stream(stream) {} virtual mongo::Status append( const mongo::logger::MessageLogDomain::EventAppender::Event& event) { _stream << event.getDate() << " " << event.getSeverity() << " " << event.getComponent() << " " << event.getContextName() << ": " << event.getMessage() << "\n"; return mongo::Status::OK(); } private: std::ostream& _stream; }; mongo::client::Options::LogAppenderPtr makeOstreamAppender(std::ostream& stream) { return mongo::client::Options::LogAppenderPtr(new OstreamAppender(stream)); } } // namespace int main(int argc, char* argv[]) { if (argc != 2) { std::cout << "usage: " << argv[0] << " MONGODB_URI" << std::endl; return EXIT_FAILURE; } const std::string uri(argv[1]); // The legacy C++ driver only has global state for SSL, and will error if // the URI has an SSL state that differs from the global state. Adjust the // global state to reflect the provided URI. mongo::client::Options options; if (uri.find("ssl=true") != std::string::npos) { options.setSSLMode(mongo::client::Options::kSSLRequired); } // Enable logging at an extremely verbose debug level. mongo::client::Options::LogAppenderFactory factory = mongo::stdx::bind(&makeOstreamAppender, boost::ref(std::cout)); options.setLogAppenderFactory(factory); options.setMinLoggedSeverity(mongo::logger::LogSeverity::Debug(5)); mongo::client::GlobalInstance instance(options); if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string errmsg; mongo::ConnectionString connectionString = mongo::ConnectionString::parse(uri, errmsg); if (!connectionString.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } const boost::scoped_ptr connection(connectionString.connect(errmsg)); if (!connection) { std::cout << "failed to connect: " << errmsg << "\n"; return EXIT_FAILURE; } bool isMaster = false; mongo::BSONObj isMasterResult; const bool isMasterCmdResult = connection->isMaster(isMaster, &isMasterResult); if (!isMasterCmdResult) { std::cout << "Error running isMaster command" << std::endl; return EXIT_FAILURE; } std::cout << "master: " << (isMaster ? "true" : "false") << "\n"; std::cout << "details: " << mongo::tojson(isMasterResult, mongo::Strict, true) << "\n"; return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/first.cpp000066400000000000000000000065421273231111400250240ustar00rootroot00000000000000// first.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * this is a good first example of how to use mongo from c++ */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include using namespace std; using namespace mongo; void insert(DBClientBase* conn, const char* name, int num) { BSONObjBuilder obj; obj.append("name", name); obj.append("num", num); conn->insert("test.people", obj.obj()); std::string e = conn->getLastError(); if (!e.empty()) { cout << "insert failed: " << e << endl; exit(EXIT_FAILURE); } } int main(int argc, const char** argv) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } { // clean up old data from any previous tests BSONObjBuilder query; conn->remove("test.people", query.obj()); } insert(conn.get(), "eliot", 15); insert(conn.get(), "sara", 23); { mongo::BSONObjBuilder query; std::auto_ptr cursor = conn->query("test.people", query.obj()); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } cout << "using cursor" << endl; while (cursor->more()) { mongo::BSONObj obj = cursor->next(); cout << "\t" << obj.jsonString() << endl; } } { mongo::BSONObjBuilder query; query.append("name", "eliot"); mongo::BSONObj res = conn->findOne("test.people", query.obj()); cout << res.isEmpty() << "\t" << res.jsonString() << endl; } { mongo::BSONObjBuilder query; query.append("name", "asd"); mongo::BSONObj res = conn->findOne("test.people", query.obj()); cout << res.isEmpty() << "\t" << res.jsonString() << endl; } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/geojson_demo.cpp000066400000000000000000000231761273231111400263470ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include #include #include "mongo/bson/bson.h" #include "mongo/client/dbclient.h" using namespace std; using namespace mongo; using namespace mongo::geo::coords2dgeographic; static const char* kDbCollectionName = "geotest.data"; static const char* kLocField = "loc"; void insertGeoData(DBClientBase* conn) { Point p1(BSON("type" << "Point" << "coordinates" << BSON_ARRAY(-5.0 << -5.0))); Point p2(BSON("type" << "Point" << "coordinates" << BSON_ARRAY(100.0 << 0.0))); Point p3(BSON("type" << "Point" << "coordinates" << BSON_ARRAY(20.0 << 30.0))); Point p4(BSON("type" << "Point" << "coordinates" << BSON_ARRAY(50.0 << 50.0))); cout << p4.toBSON().jsonString() << endl; BSONObj lineBson = BSON("type" << "LineString" << "coordinates" << BSON_ARRAY(BSON_ARRAY(0.0 << 10.0) << BSON_ARRAY(100.0 << 10.0))); LineString line(lineBson); std::vector lineStrings; lineStrings.push_back(line); lineStrings.push_back(line); MultiLineString mls(lineStrings); geo::coords2dgeographic::Polygon poly(lineStrings); BSONObj mpBson = BSON("type" << "MultiPolygon" << "coordinates" << BSON_ARRAY(BSON_ARRAY(BSON_ARRAY( BSON_ARRAY(0.0 << 10.0) << BSON_ARRAY(100.0 << 10.0) << BSON_ARRAY(5.0 << 5.0) << BSON_ARRAY(0.0 << 10.0))))); cout << "MULTIPOLYGON BSON:" << endl; cout << mpBson.jsonString() << endl; MultiPolygon mp(mpBson); cout << mp.toBSON().jsonString() << endl; BSONObj gcolBson = BSON("type" << "GeometryCollection" << "geometries" << BSON_ARRAY(p1.toBSON() << p2.toBSON() << line.toBSON())); GeometryCollection gcol(gcolBson); cout << "GEO COLLECTION BSON:" << endl; cout << gcol.toBSON() << endl; const vector& geoms = gcol.getGeometries(); for (size_t i = 0; i < geoms.size(); ++i) { cout << geoms[i]->getType() << endl; } conn->insert(kDbCollectionName, BSON(kLocField << p1.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << p2.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << p3.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << p4.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << line.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << mls.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << mp.toBSON())); conn->insert(kDbCollectionName, BSON(kLocField << gcol.toBSON())); conn->createIndex(kDbCollectionName, fromjson("{loc:\"2dsphere\"}")); cout << "Coordinates p1 toBSON().toString():" << endl; cout << p1.getCoordinates().toBSON().toString() << endl; cout << "MultiLineString mls toBSON().jsonString():" << endl; cout << mls.toBSON().jsonString() << endl << endl; } void queryGeoData(DBClientBase* conn) { BSONObj lineBson = BSON("type" << "LineString" << "coordinates" << BSON_ARRAY(BSON_ARRAY(0.0 << 0.0) << BSON_ARRAY(50.0 << 50.0))); LineString line(lineBson); Query q = MONGO_QUERY(kLocField << WITHINQUERY(line.getBoundingBox())); Query q2 = MONGO_QUERY(kLocField << INTERSECTSQUERY(line)); BSONObj multipointBson = BSON("type" << "MultiPoint" << "coordinates" << BSON_ARRAY(BSON_ARRAY(0.0 << 0.0) << BSON_ARRAY(50.0 << 50.0))); MultiPoint mPoint(multipointBson); Query q3 = MONGO_QUERY(kLocField << WITHINQUERY(mPoint.getBoundingBox())); Query q4 = MONGO_QUERY(kLocField << INTERSECTSQUERY(mPoint)); BSONObj polygonBson = BSON("type" << "Polygon" << "coordinates" << BSON_ARRAY( // list of linear rings BSON_ARRAY( // a single linear ring BSON_ARRAY(0.0 << 0.0) << BSON_ARRAY(0.0 << 50.0) << BSON_ARRAY(80.0 << 80.0) << BSON_ARRAY(0.0 << 0.0)))); geo::coords2dgeographic::Polygon poly(polygonBson); // Make sure printing is ok: cout << "LineString json:" << endl; cout << line.toBSON().jsonString() << endl; cout << "MultiPoint json:" << endl; cout << mPoint.toBSON().jsonString() << endl; cout << "Polygon json:" << endl; cout << poly.toBSON().jsonString() << endl; cout << endl << endl; Query q5 = MONGO_QUERY(kLocField << WITHINQUERY(poly.getBoundingBox())); Query q6 = MONGO_QUERY(kLocField << INTERSECTSQUERY(poly)); geo::Coordinates2DGeographic coords(1, 2); geo::coords2dgeographic::Point point(coords); Query nearQuery = MONGO_QUERY(kLocField << NEARQUERY(point, 0.5)); Query nearSphereQuery = MONGO_QUERY(kLocField << NEARSPHEREQUERY(point, 0.5)); cout << "*** Testing LineString ***" << endl; auto_ptr cursor = conn->query(kDbCollectionName, q); cout << "Results from WITHINQUERY" << endl; while (cursor->more()) cout << cursor->next().toString() << endl; cout << "---------------" << endl; auto_ptr cursor2 = conn->query(kDbCollectionName, q2); cout << "Results from INTERSECTSQUERY" << endl; while (cursor2->more()) cout << cursor2->next().toString() << endl; cout << "---------------" << endl; cout << "*** Testing MultiPoint ***" << endl; auto_ptr cursor3 = conn->query(kDbCollectionName, q3); cout << "Results from WITHINQUERY" << endl; while (cursor3->more()) cout << cursor3->next().toString() << endl; cout << "---------------" << endl; auto_ptr cursor4 = conn->query(kDbCollectionName, q4); cout << "Results from INTERSECTSQUERY" << endl; while (cursor4->more()) cout << cursor4->next().toString() << endl; cout << "---------------" << endl; cout << "*** Testing Polygon ***" << endl; auto_ptr cursor5 = conn->query(kDbCollectionName, q5); cout << "Results from GEOWITHIN" << endl; while (cursor5->more()) cout << cursor5->next().toString() << endl; cout << "---------------" << endl; auto_ptr cursor6 = conn->query(kDbCollectionName, q6); cout << "Results from INTERSECTSQUERY" << endl; while (cursor6->more()) cout << cursor6->next().toString() << endl; cout << "---------------" << endl; auto_ptr nearQueryCursor = conn->query(kDbCollectionName, nearQuery); cout << "Results from NEAR" << endl; while (nearQueryCursor->more()) cout << nearQueryCursor->next().toString() << endl; cout << "---------------" << endl; auto_ptr nearSphereQueryCursor = conn->query(kDbCollectionName, nearSphereQuery); cout << "Results from NEARSPHERE" << endl; while (nearSphereQueryCursor->more()) cout << nearSphereQueryCursor->next().toString() << endl; cout << "---------------" << endl; } int main(int argc, const char** argv) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } try { BSONObj cmdResult; conn->runCommand("admin", BSON("buildinfo" << true), cmdResult); if (cmdResult["versionArray"].Array()[1].Int() < 6) return EXIT_SUCCESS; insertGeoData(conn.get()); queryGeoData(conn.get()); conn->dropCollection(kDbCollectionName); } catch (const DBException& dbe) { cout << "caught DBException " << dbe.toString() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/initializeTest.cpp000066400000000000000000000050471273231111400266750ustar00rootroot00000000000000// initializeTest.cpp /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include using namespace std; using namespace mongo; void successfulInit(client::Options opts) { Status status = client::initialize(opts); if (!status.isOK()) { throw std::runtime_error("Failed to initialize the driver"); } } void failedInit(string errMsg) { Status status = client::initialize(); if (status.isOK()) { throw std::runtime_error(errMsg); } } void successfulShutdown() { Status status = client::shutdown(); if (!status.isOK()) { throw std::runtime_error("Failed to shutdown properly"); } } void failedShutdown(string errMsg) { Status status = client::shutdown(); if (status.isOK()) { throw std::runtime_error(errMsg); } } int main() { client::Options manualShutdownOpts = client::Options(); manualShutdownOpts.setCallShutdownAtExit(false); try { // shutdown before initializing, should fail failedShutdown("shouldn't shutdown before initializing"); // first initialize, should succeed successfulInit(manualShutdownOpts); // shutdown, should succeed successfulShutdown(); // shutdown again, should fail failedShutdown("Can't shutdown, driver has already been terminated"); // another initialization, should fail failedInit("Can't initialize, driver has already been terminated"); // a final shutdown, should also fail failedShutdown("Can't shutdown, driver has already been terminated"); } catch (const std::runtime_error& e) { cout << e.what() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/insert_demo.cpp000066400000000000000000000051161273231111400262010ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" // the mongo c++ driver #include using namespace std; using namespace mongo; int main(int argc, char* argv[]) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } try { BSONObj o = BSON("hello" << "world"); cout << "dropping collection..." << endl; conn->dropCollection("test.foo"); cout << "inserting..." << endl; time_t start = time(0); for (unsigned i = 0; i < 100000; i++) { conn->insert("test.foo", o); } // wait until all operations applied cout << "getlasterror returns: \"" << conn->getLastError() << '"' << endl; time_t done = time(0); time_t dt = done - start; cout << dt << " seconds " << 100000 / dt << " per second" << endl; } catch (DBException& e) { cout << "caught DBException " << e.toString() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/loggingTest.cpp000066400000000000000000000065061273231111400261630ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined(_WIN32) #include #include #endif #include #include "mongo/client/dbclient.h" #include "mongo/stdx/functional.h" // NOTE: // log.h is a private header and is not meant to be included in user // applications. We include it here only as a test, to simulate the // driver's internal logging functionality. #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault; #include "mongo/util/log.h" #ifndef verify #define verify(x) MONGO_verify(x) #endif using namespace std; using namespace mongo; using namespace logger; namespace { // A demonstration of how to inject a custom logger into the client driver. This class // counts logging events generated by the driver. Note that the appender is responsible for // its own synchronization, so the counter is an atomic. class CountAppender : public MessageLogDomain::EventAppender { public: explicit CountAppender(AtomicWord* counter) : _count(counter) {} virtual Status append(const MessageLogDomain::EventAppender::Event& event) { if (event.getMessage().find("[COUNT]") != string::npos) { _count->fetchAndAdd(1); } return Status::OK(); } int getCount() { return _count->load(); } private: AtomicWord* _count; }; // A factory function to return an instance of our appender. client::Options::LogAppenderPtr makeCountAppender(AtomicWord* counter) { return client::Options::LogAppenderPtr(new CountAppender(counter)); } } // namespace int main() { client::Options loggingOpts = client::Options(); AtomicWord logCounter; // add an appender client::Options::LogAppenderFactory factory = stdx::bind(&makeCountAppender, &logCounter); loggingOpts.setLogAppenderFactory(factory); verify(loggingOpts.logAppenderFactory()); // set the logging level twice, see that the later one sticks LogSeverity level1 = LogSeverity::Debug(2); loggingOpts.setMinLoggedSeverity(level1); verify(loggingOpts.minLoggedSeverity() == level1); LogSeverity level2 = LogSeverity::Debug(1); loggingOpts.setMinLoggedSeverity(level2); verify(loggingOpts.minLoggedSeverity() == level2); mongo::client::GlobalInstance instance(loggingOpts); if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << endl; return EXIT_FAILURE; } // Check that logging is working as expected MONGO_LOG(3) << "[COUNT] I'm a log message!" << endl; MONGO_LOG(2) << "[COUNT] Quick, run!" << endl; MONGO_LOG(1) << "[COUNT] Phew, the coast is clear." << endl; MONGO_LOG(0) << "[COUNT] Excellent." << endl; verify(logCounter.load() == 2); return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/rs.cpp000066400000000000000000000077561273231111400243310ustar00rootroot00000000000000// rs.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * example of using replica sets from c++ */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #include #include using namespace mongo; using namespace std; void workerThread(string collName, bool print, DBClientReplicaSet* conn) { while (true) { try { conn->update(collName, BSONObj(), BSON("$inc" << BSON("x" << 1)), true); BSONObj x = conn->findOne(collName, BSONObj()); if (print) { cout << x << endl; } BSONObj a = conn->slaveConn().findOne(collName, BSONObj(), 0, QueryOption_SlaveOk); BSONObj b = conn->findOne(collName, BSONObj(), 0, QueryOption_SlaveOk); if (print) { cout << "\t A " << a << endl; cout << "\t B " << b << endl; } } catch (std::exception& e) { cout << "ERROR: " << e.what() << endl; } sleepmillis(10); } } int main(int argc, const char** argv) { unsigned nThreads = 1; bool print = false; bool testTimeout = false; for (int i = 1; i < argc; i++) { if (mongoutils::str::equals("--threads", argv[i])) { nThreads = atoi(argv[++i]); } else if (mongoutils::str::equals("--print", argv[i])) { print = true; } // Run a special mode to demonstrate the DBClientReplicaSet so_timeout option. else if (mongoutils::str::equals("--testTimeout", argv[i])) { testTimeout = true; } else { cerr << "unknown option: " << argv[i] << endl; return EXIT_FAILURE; } } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << endl; return EXIT_FAILURE; } string errmsg; ConnectionString cs = ConnectionString::parse("mongodb://127.0.0.1/?replicaSet=foo", errmsg); if (!cs.isValid()) { cout << "error parsing url: " << errmsg << endl; return EXIT_FAILURE; } DBClientReplicaSet* conn = static_cast(cs.connect(errmsg, testTimeout ? 10 : 0)); if (!conn) { cout << "error connecting: " << errmsg << endl; return EXIT_FAILURE; } string collName = "test.rs1"; conn->dropCollection(collName); if (testTimeout) { conn->insert(collName, BSONObj()); try { conn->count(collName, BSON("$where" << "sleep(40000)")); } catch (DBException&) { return EXIT_SUCCESS; } cout << "expected socket exception" << endl; return EXIT_FAILURE; } vector > threads; for (unsigned i = 0; i < nThreads; i++) { string errmsg; threads.push_back(boost::shared_ptr(new boost::thread(boost::bind( workerThread, collName, print, static_cast(cs.connect(errmsg)))))); } for (unsigned i = 0; i < threads.size(); i++) { threads[i]->join(); } return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/second.cpp000066400000000000000000000050471273231111400251470ustar00rootroot00000000000000// second.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include using namespace std; using namespace mongo; int main(int argc, const char** argv) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } const char* ns = "test.second"; conn->remove(ns, BSONObj()); conn->insert(ns, BSON("name" << "eliot" << "num" << 17)); conn->insert(ns, BSON("name" << "sara" << "num" << 24)); std::auto_ptr cursor = conn->query(ns, BSONObj()); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } cout << "using cursor" << endl; while (cursor->more()) { BSONObj obj = cursor->next(); cout << "\t" << obj.jsonString() << endl; } conn->createIndex(ns, BSON("name" << 1 << "num" << -1)); return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/simple_client_demo.cpp000066400000000000000000000056451273231111400275330ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // See also : http://dochub.mongodb.org/core/cppdrivertutorial // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" // the mongo c++ driver #include using namespace std; using namespace mongo; int main(int argc, char* argv[]) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } try { unsigned long long count = conn->count("test.foo"); cout << "count of exiting documents in collection test.foo : " << count << endl; conn->remove("test.foo", BSONObj()); BSONObj o = BSON("hello" << "world"); conn->insert("test.foo", o); string e = conn->getLastError(); if (!e.empty()) { cout << "insert #1 failed: " << e << endl; } // make an index with a unique key constraint conn->createIndex("test.foo", IndexSpec().addKeys(BSON("hello" << 1)).unique()); try { conn->insert("test.foo", o); // will cause a dup key error on "hello" field } catch (const OperationException&) { // duplicate key error } cout << "we expect a dup key error here:" << endl; cout << " " << conn->getLastErrorDetailed().toString() << endl; } catch (DBException& e) { cout << "caught DBException " << e.toString() << endl; return 1; } return 0; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/tail.cpp000066400000000000000000000030601273231111400246160ustar00rootroot00000000000000// tail.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* example of using a tailable cursor */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include "mongo/util/goodies.h" using namespace mongo; void tail(DBClientBase& conn, const char* ns) { BSONElement lastId = minKey.firstElement(); Query query = Query(); auto_ptr c = conn.query(ns, query, 0, 0, 0, QueryOption_CursorTailable); while (1) { if (!c->more()) { if (c->isDead()) { break; // we need to requery } // all data (so far) exhausted, wait for more sleepsecs(1); continue; } BSONObj o = c->next(); lastId = o["_id"]; cout << o.toString() << endl; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/tutorial.cpp000066400000000000000000000071761273231111400255440ustar00rootroot00000000000000// tutorial.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include using namespace std; using namespace mongo; int printIfAge(DBClientBase* conn, int age) { std::auto_ptr cursor = conn->query("tutorial.persons", MONGO_QUERY("age" << age).sort("name")); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } while (cursor->more()) { BSONObj p = cursor->next(); cout << p.getStringField("name") << endl; } return EXIT_SUCCESS; } int run(DBClientBase* conn) { cout << "connected ok" << endl; BSONObj p = BSON("name" << "Joe" << "age" << 33); conn->insert("tutorial.persons", p); p = BSON("name" << "Jane" << "age" << 40); conn->insert("tutorial.persons", p); p = BSON("name" << "Abe" << "age" << 33); conn->insert("tutorial.persons", p); p = BSON("name" << "Methuselah" << "age" << BSONNULL); conn->insert("tutorial.persons", p); p = BSON("name" << "Samantha" << "age" << 21 << "city" << "Los Angeles" << "state" << "CA"); conn->insert("tutorial.persons", p); conn->createIndex("tutorial.persons", fromjson("{age:1}")); cout << "count:" << conn->count("tutorial.persons") << endl; std::auto_ptr cursor = conn->query("tutorial.persons", BSONObj()); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } while (cursor->more()) { cout << cursor->next().toString() << endl; } cout << "\nprintifage:\n"; return printIfAge(conn, 33); } int main(int argc, char* argv[]) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } int ret = EXIT_SUCCESS; try { ret = run(conn.get()); } catch (DBException& e) { cout << "caught " << e.what() << endl; ret = EXIT_FAILURE; } return ret; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/examples/whereExample.cpp000066400000000000000000000060751273231111400263240ustar00rootroot00000000000000// @file whereExample.cpp // @see http://dochub.mongodb.org/core/serversidecodeexecution /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include "mongo/client/dbclient.h" #include #ifndef verify #define verify(x) MONGO_verify(x) #endif using namespace std; using namespace mongo; int main(int argc, const char** argv) { if (argc > 2) { std::cout << "usage: " << argv[0] << " [MONGODB_URI]" << std::endl; return EXIT_FAILURE; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cout << "failed to initialize the client driver: " << instance.status() << std::endl; return EXIT_FAILURE; } std::string uri = argc == 2 ? argv[1] : "mongodb://localhost:27017"; std::string errmsg; ConnectionString cs = ConnectionString::parse(uri, errmsg); if (!cs.isValid()) { std::cout << "Error parsing connection string " << uri << ": " << errmsg << std::endl; return EXIT_FAILURE; } boost::scoped_ptr conn(cs.connect(errmsg)); if (!conn) { cout << "couldn't connect : " << errmsg << endl; return EXIT_FAILURE; } const char* ns = "test.where"; conn->remove(ns, BSONObj()); conn->insert(ns, BSON("name" << "eliot" << "num" << 17)); conn->insert(ns, BSON("name" << "sara" << "num" << 24)); std::auto_ptr cursor = conn->query(ns, BSONObj()); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } while (cursor->more()) { BSONObj obj = cursor->next(); cout << "\t" << obj.jsonString() << endl; } cout << "now using $where" << endl; Query q = Query("{}").where("this.name == name", BSON("name" << "sara")); cursor = conn->query(ns, q); if (!cursor.get()) { cout << "query failure" << endl; return EXIT_FAILURE; } int num = 0; while (cursor->more()) { BSONObj obj = cursor->next(); cout << "\t" << obj.jsonString() << endl; num++; } verify(num == 1); return EXIT_SUCCESS; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/exceptions.cpp000066400000000000000000000017131273231111400242330ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/exceptions.h" namespace mongo { namespace { const char kName[] = "OperationException"; } OperationException::OperationException(const BSONObj& errorObj) : DBException(std::string(kName) + ": " + errorObj.toString(), 0), _lastError(errorObj) {} OperationException::~OperationException() throw() {} } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/exceptions.h000066400000000000000000000025651273231111400237060ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/db/jsobj.h" #include "mongo/util/assert_util.h" namespace mongo { /** * General runtime exception generated by the MongoDB client driver. */ class MONGO_CLIENT_API OperationException : public DBException { public: /** Takes a BSONObj that is the result of the "getlasterror" command */ OperationException(const BSONObj& errorObj); /** Required due to BSONObj member desctructor not specifying throw() */ virtual ~OperationException() throw(); /** Get the last_error object representing the operation exception */ const BSONObj& obj() const { return _lastError; } private: const BSONObj _lastError; const std::string _errorString; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/export_macros.h000066400000000000000000000032401273231111400244010ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/platform/compiler.h" #define MONGO_CLIENT_FUNC MONGO_COMPILER_API_CALLING_CONVENTION /** * Definition of macros used to label the mongo client api. * * If a type, free function or global variable is part of the client api, it must be labeled. * * To label a type, place the MONGO_CLIENT_API macro after the struct, class or enum keyword. * Example: * class MONGO_CLIENT_API DBClientInterface { ... }; * * To label a function, place the label on the declaration before the return type. You * do NOT need to label the methods of exported classes. * Example: * MONGO_CLIENT_API Status myFreeFunction(int arg1); * * To label a global variable, place the label on the declaration, before the type and * after the "extern" keyword. * Example: * extern MONGO_CLIENT_API int myGlobalVariable; * */ #if defined(STATIC_LIBMONGOCLIENT) #define MONGO_CLIENT_API #else #if defined(LIBMONGOCLIENT_BUILDING) #define MONGO_CLIENT_API MONGO_COMPILER_API_EXPORT #else #define MONGO_CLIENT_API MONGO_COMPILER_API_IMPORT #endif #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/client/gridfs.cpp000066400000000000000000000245301273231111400233320ustar00rootroot00000000000000// gridfs.cpp /* Copyright 2009 10gen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/gridfs.h" #include #include #include #include #include #include #if defined(_WIN32) #include #endif #include "mongo/client/dbclientcursor.h" #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif namespace mongo { using std::min; using std::auto_ptr; using std::cout; using std::ios; using std::ofstream; using std::ostream; using std::string; const unsigned DEFAULT_CHUNK_SIZE = 255 * 1024; GridFSChunk::GridFSChunk(BSONObj o) { _data = o; } GridFSChunk::GridFSChunk(BSONObj fileObject, int chunkNumber, const char* data, int len) { BSONObjBuilder b; b.appendAs(fileObject["_id"], "files_id"); b.append("n", chunkNumber); b.appendBinData("data", len, BinDataGeneral, data); _data = b.obj(); } GridFS::GridFS(DBClientBase& client, const string& dbName, const string& prefix) : _client(client), _dbName(dbName), _prefix(prefix) { _filesNS = dbName + "." + prefix + ".files"; _chunksNS = dbName + "." + prefix + ".chunks"; _chunkSize = DEFAULT_CHUNK_SIZE; client.createIndex(_filesNS, BSON("filename" << 1)); client.createIndex(_chunksNS, IndexSpec().addKeys(BSON("files_id" << 1 << "n" << 1)).unique()); } GridFS::~GridFS() {} void GridFS::setChunkSize(unsigned int size) { massert(13296, "invalid chunk size is specified", (size != 0)); _chunkSize = size; } unsigned int GridFS::getChunkSize() const { return _chunkSize; } BSONObj GridFS::storeFile(const char* data, size_t length, const string& remoteName, const string& contentType) { char const* const end = data + length; OID id; id.init(); BSONObj idObj = BSON("_id" << id); int chunkNumber = 0; while (data < end) { int chunkLen = MIN(_chunkSize, (unsigned)(end - data)); GridFSChunk c(idObj, chunkNumber, data, chunkLen); _client.insert(_chunksNS.c_str(), c._data); chunkNumber++; data += chunkLen; } return insertFile(remoteName, id, length, contentType); } BSONObj GridFS::storeFile(const string& fileName, const string& remoteName, const string& contentType) { FILE* fd; if (fileName == "-") fd = stdin; else fd = fopen(fileName.c_str(), "rb"); uassert(10013, "error opening file", fd); OID id; id.init(); BSONObj idObj = BSON("_id" << id); int chunkNumber = 0; gridfs_offset length = 0; while (!feof(fd)) { // boost::scoped_arraybuf (new char[_chunkSize+1]); char* buf = new char[_chunkSize + 1]; char* bufPos = buf; //.get(); unsigned int chunkLen = 0; // how much in the chunk now while (chunkLen != _chunkSize && !feof(fd)) { int readLen = fread(bufPos, 1, _chunkSize - chunkLen, fd); chunkLen += readLen; bufPos += readLen; verify(chunkLen <= _chunkSize); } GridFSChunk c(idObj, chunkNumber, buf, chunkLen); _client.insert(_chunksNS.c_str(), c._data); length += chunkLen; chunkNumber++; delete[] buf; } if (fd != stdin) fclose(fd); return insertFile((remoteName.empty() ? fileName : remoteName), id, length, contentType); } BSONObj GridFS::insertFile(const string& name, const OID& id, gridfs_offset length, const string& contentType) { // Wait for any pending writebacks to finish BSONObj errObj = _client.getLastErrorDetailed(); uassert(16428, str::stream() << "Error storing GridFS chunk for file: " << name << ", error: " << errObj, DBClientWithCommands::getLastErrorString(errObj) == ""); BSONObj res; if (!_client.runCommand(_dbName.c_str(), BSON("filemd5" << id << "root" << _prefix), res)) throw UserException(9008, "filemd5 failed"); BSONObjBuilder file; file << "_id" << id << "filename" << name << "chunkSize" << _chunkSize << "uploadDate" << DATENOW << "md5" << res["md5"]; if (length < 1024 * 1024 * 1024) { // 2^30 file << "length" << (int)length; } else { file << "length" << (long long)length; } if (!contentType.empty()) file << "contentType" << contentType; BSONObj ret = file.obj(); _client.insert(_filesNS.c_str(), ret); return ret; } void GridFS::removeFile(const string& fileName) { auto_ptr files = _client.query(_filesNS, BSON("filename" << fileName)); if (files.get()) { while (files->more()) { BSONObj file = files->next(); BSONElement id = file["_id"]; _client.remove(_filesNS.c_str(), BSON("_id" << id)); _client.remove(_chunksNS.c_str(), BSON("files_id" << id)); } } } GridFile::GridFile(const GridFS* grid, BSONObj obj) { _grid = grid; _obj = obj; } GridFile GridFS::findFileByName(const string& fileName) const { return findFile(BSON("filename" << fileName)); }; GridFile GridFS::findFile(Query query) const { query.sort(BSON("uploadDate" << -1)); return GridFile(this, _client.findOne(_filesNS.c_str(), query.obj)); } auto_ptr GridFS::list() const { return _client.query(_filesNS.c_str(), BSONObj()); } auto_ptr GridFS::list(BSONObj o) const { return _client.query(_filesNS.c_str(), o); } void GridFS::_insertChunk(const GridFSChunk& chunk) { _client.insert(_chunksNS.c_str(), chunk._data); } BSONObj GridFile::getMetadata() const { BSONElement meta_element = _obj["metadata"]; if (meta_element.eoo()) { return BSONObj(); } return meta_element.embeddedObject(); } GridFSChunk GridFile::getChunk(int n) const { _exists(); BSONObjBuilder b; b.appendAs(_obj["_id"], "files_id"); b.append("n", n); BSONObj o = _grid->_client.findOne(_grid->_chunksNS.c_str(), b.obj()); uassert(10014, "chunk is empty!", !o.isEmpty()); return GridFSChunk(o); } gridfs_offset GridFile::write(ostream& out) const { _exists(); const int num = getNumChunks(); for (int i = 0; i < num; i++) { GridFSChunk c = getChunk(i); int len; const char* data = c.data(len); out.write(data, len); } return getContentLength(); } gridfs_offset GridFile::write(const string& where) const { if (where == "-") { return write(cout); } else { ofstream out(where.c_str(), ios::out | ios::binary); uassert(13325, "couldn't open file: " + where, out.is_open()); return write(out); } } void GridFile::_exists() const { uassert(10015, "doesn't exists", exists()); } GridFileBuilder::GridFileBuilder(GridFS* const grid) : _grid(grid), _chunkSize(grid->getChunkSize()), _currentChunk(0), _pendingData(new char[_chunkSize]), _pendingDataSize(0), _fileLength(0) { _fileId.init(); _fileIdObj = BSON("_id" << _fileId); } const char* GridFileBuilder::_appendChunk(const char* data, size_t length, bool forcePendingInsert) { const char* const end = data + length; while (data < end) { size_t chunkLen = min(_chunkSize, static_cast(end - data)); // the last chunk needs to be stored as pendingData, break while if // necessary if ((chunkLen < _chunkSize) && (!forcePendingInsert)) break; GridFSChunk chunk(_fileIdObj, _currentChunk, data, chunkLen); _grid->_insertChunk(chunk); ++_currentChunk; data += chunkLen; _fileLength += chunkLen; } return data; } void GridFileBuilder::_appendPendingData() { if (_pendingDataSize > 0) { _appendChunk(_pendingData.get(), _pendingDataSize, true); _pendingDataSize = 0; } } void GridFileBuilder::appendChunk(const char* data, size_t length) { if (length == 0) return; // check if there is pending data if (_pendingDataSize > 0) { size_t totalSize = _pendingDataSize + length; size_t size = min(_chunkSize, totalSize) - _pendingDataSize; memcpy(_pendingData.get() + _pendingDataSize, data, size); _pendingDataSize += size; invariant(_pendingDataSize <= _chunkSize); if (_pendingDataSize == _chunkSize) { _appendPendingData(); const char* const end = data + length; data = _appendChunk(data + size, length - size, false); if (data != end) { invariant(data < end); size_t nsize = static_cast(end - data); memcpy(_pendingData.get() + _pendingDataSize, data, nsize); _pendingDataSize += nsize; } } } else { const char* const end = data + length; // split data in _chunkSize blocks, and store as pending the last block if // necessary data = _appendChunk(data, length, false); // process pending data if necessary if (data != end) { size_t size = static_cast(end - data); memcpy(_pendingData.get() + _pendingDataSize, data, size); _pendingDataSize += size; } } } BSONObj GridFileBuilder::buildFile(const string& remoteName, const string& contentType) { _appendPendingData(); BSONObj ret = _grid->insertFile(remoteName, _fileId, _fileLength, contentType); // resets the object to allow more data append for a GridFile _currentChunk = 0; _pendingDataSize = 0; _fileLength = 0; _fileId.init(); _fileIdObj = BSON("_id" << _fileId); return ret; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/gridfs.h000066400000000000000000000165661273231111400230110ustar00rootroot00000000000000/** @file gridfs.h */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "boost/scoped_array.hpp" #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonobj.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/export_macros.h" namespace mongo { typedef unsigned long long gridfs_offset; class GridFS; class GridFile; class GridFileBuilder; class MONGO_CLIENT_API GridFSChunk { public: GridFSChunk(BSONObj data); GridFSChunk(BSONObj fileId, int chunkNumber, const char* data, int len); int len() const { int len; _data["data"].binDataClean(len); return len; } const char* data(int& len) const { return _data["data"].binDataClean(len); } private: BSONObj _data; friend class GridFS; }; /** GridFS is for storing large file-style objects in MongoDB. @see http://dochub.mongodb.org/core/gridfsspec */ class MONGO_CLIENT_API GridFS { public: /** * @param client - db connection * @param dbName - root database name * @param prefix - if you want your data somewhere besides .fs */ GridFS(DBClientBase& client, const std::string& dbName, const std::string& prefix = "fs"); ~GridFS(); /** * @param */ void setChunkSize(unsigned int size); unsigned int getChunkSize() const; /** * puts the file reference by fileName into the db * @param fileName local filename relative to process * @param remoteName optional filename to use for file stored in GridFS * (default is to use fileName parameter) * @param contentType optional MIME type for this object. * (default is to omit) * @return the file object */ BSONObj storeFile(const std::string& fileName, const std::string& remoteName = "", const std::string& contentType = ""); /** * puts the file represented by data into the db * @param data pointer to buffer to store in GridFS * @param length length of buffer * @param remoteName filename to use for file stored in GridFS * @param contentType optional MIME type for this object. * (default is to omit) * @return the file object */ BSONObj storeFile(const char* data, size_t length, const std::string& remoteName, const std::string& contentType = ""); /** * removes file referenced by fileName from the db * @param fileName filename (in GridFS) of the file to remove * @return the file object */ void removeFile(const std::string& fileName); /** * returns a file object matching the query */ GridFile findFile(Query query) const; /** * equiv to findFile( { filename : filename } ) */ GridFile findFileByName(const std::string& fileName) const; /** * convenience method to get all the files */ std::auto_ptr list() const; /** * convenience method to get all the files with a filter */ std::auto_ptr list(BSONObj query) const; private: DBClientBase& _client; std::string _dbName; std::string _prefix; std::string _filesNS; std::string _chunksNS; unsigned int _chunkSize; // insert fileobject. All chunks must be in DB. BSONObj insertFile(const std::string& name, const OID& id, gridfs_offset length, const std::string& contentType); // Insert a chunk into DB, this method is intended to be used by // GridFileBuilder to incrementally insert chunks void _insertChunk(const GridFSChunk& chunk); friend class GridFile; friend class GridFileBuilder; }; /** wrapper for a file stored in the Mongo database */ class MONGO_CLIENT_API GridFile { public: /** * @return whether or not this file exists * findFile will always return a GriFile, so need to check this */ bool exists() const { return !_obj.isEmpty(); } std::string getFilename() const { return _obj["filename"].str(); } int getChunkSize() const { return (int)(_obj["chunkSize"].number()); } gridfs_offset getContentLength() const { return (gridfs_offset)(_obj["length"].number()); } std::string getContentType() const { return _obj["contentType"].valuestr(); } Date_t getUploadDate() const { return _obj["uploadDate"].date(); } std::string getMD5() const { return _obj["md5"].str(); } BSONElement getFileField(const std::string& name) const { return _obj[name]; } BSONObj getMetadata() const; int getNumChunks() const { return (int)ceil((double)getContentLength() / (double)getChunkSize()); } GridFSChunk getChunk(int n) const; /** write the file to the output stream */ gridfs_offset write(std::ostream& out) const; /** write the file to this filename */ gridfs_offset write(const std::string& where) const; private: GridFile(const GridFS* grid, BSONObj obj); void _exists() const; const GridFS* _grid; BSONObj _obj; friend class GridFS; }; /** * class which allow to build GridFiles in a stream fashion way */ class MONGO_CLIENT_API GridFileBuilder { public: /** * @param grid - gridfs instance */ GridFileBuilder(GridFS* const grid); /** * Appends a chunk of data. Data will be split as many times as * necessary in chunkSize blocks. Sizes not multiple of chunkSize will * copy the reamining bytes to a pendingData pointer. In this way, * it is possible to add data in a stream fashion way. * @param data - C string with data * @param length - size of the string */ void appendChunk(const char* data, size_t length); /** * Inserts the description of the file in GridFS collection. Note that * the stream will be reinitialized after the build call, so it will be * possible to continue appending data to build another file. * @param remoteName filename to use for file stored in GridFS * @param contentType optional MIME type for this object. * (default is to omit) * @return the file object */ mongo::BSONObj buildFile(const std::string& remoteName, const std::string& contentType = ""); private: GridFS* const _grid; const size_t _chunkSize; // taken from GridFS in the constructor unsigned int _currentChunk; OID _fileId; BSONObj _fileIdObj; boost::scoped_array _pendingData; // pointer with _chunkSize space size_t _pendingDataSize; gridfs_offset _fileLength; const char* _appendChunk(const char* data, size_t length, bool forcePendingInsert); void _appendPendingData(); }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/include_bsonh_test.cpp000066400000000000000000000015761273231111400257340ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include int main() { return 0; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/include_dbclienth_test.cpp000066400000000000000000000016041273231111400265470ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // It is the responsibility of the mongo client consumer to ensure that any necessary windows // headers have already been included before including the driver facade headers. #if defined(_WIN32) #include #include #endif #include int main() { return 0; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/index_spec.cpp000066400000000000000000000154611273231111400242000ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/index_spec.h" #include "mongo/client/dbclientinterface.h" namespace mongo { const char IndexSpec::kIndexValText[] = "text"; const char IndexSpec::kIndexValGeo2D[] = "2d"; const char IndexSpec::kIndexValGeoHaystack[] = "geoHaystack"; const char IndexSpec::kIndexValGeo2DSphere[] = "2dsphere"; const char IndexSpec::kIndexValHashed[] = "hashed"; namespace { const int kIndexTypeNumbers[] = {IndexSpec::kIndexValAscending, IndexSpec::kIndexValDescending}; const char* const kIndexTypeStrings[] = {NULL, NULL, IndexSpec::kIndexValText, IndexSpec::kIndexValGeo2D, IndexSpec::kIndexValGeoHaystack, IndexSpec::kIndexValGeo2DSphere, IndexSpec::kIndexValHashed}; const char kDuplicateKey[] = "duplicate key added to index descriptor"; const char kDuplicateOption[] = "duplicate option added to index descriptor"; } // namespace IndexSpec::IndexSpec() : _dynamicName(true) {} IndexSpec& IndexSpec::addKey(const StringData& field, IndexType type) { uassert(0, kDuplicateKey, !_keys.asTempObj().hasField(field)); if (type <= kIndexTypeDescending) _keys.append(field, kIndexTypeNumbers[type]); else _keys.append(field, kIndexTypeStrings[type]); _rename(); return *this; } IndexSpec& IndexSpec::addKey(const BSONElement& fieldAndType) { uassert(0, kDuplicateKey, !_keys.asTempObj().hasField(fieldAndType.fieldName())); _keys.append(fieldAndType); _rename(); return *this; } IndexSpec& IndexSpec::addKeys(const KeyVector& keys) { KeyVector::const_iterator where = keys.begin(); const KeyVector::const_iterator end = keys.end(); for (; where != end; ++where) addKey(where->first, where->second); return *this; } IndexSpec& IndexSpec::addKeys(const BSONObj& keys) { BSONObjIterator iter(keys); while (iter.more()) addKey(iter.next()); return *this; } IndexSpec& IndexSpec::background(bool value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("background")); _options.append("background", value); return *this; } IndexSpec& IndexSpec::unique(bool value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("unique")); _options.append("unique", value); return *this; } IndexSpec& IndexSpec::name(const StringData& value) { _name = value.toString(); _dynamicName = false; return *this; } IndexSpec& IndexSpec::dropDuplicates(bool value) { return dropDuplicatesDeprecated(value); } IndexSpec& IndexSpec::dropDuplicatesDeprecated(bool value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("dropDups")); _options.append("dropDups", value); return *this; } IndexSpec& IndexSpec::sparse(bool value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("sparse")); _options.append("sparse", value); return *this; } IndexSpec& IndexSpec::expireAfterSeconds(int value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("expireAfterSeconds")); _options.append("expireAfterSeconds", value); return *this; } IndexSpec& IndexSpec::version(int value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("v")); _options.append("v", value); return *this; } IndexSpec& IndexSpec::partialFilterExpression(const BSONObj& value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("partialFilterExpression")); _options.append("partialFilterExpression", value); return *this; } IndexSpec& IndexSpec::textWeights(const BSONObj& value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("weights")); _options.append("weights", value); return *this; } IndexSpec& IndexSpec::textDefaultLanguage(const StringData& value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("default_language")); _options.append("default_language", value); return *this; } IndexSpec& IndexSpec::textLanguageOverride(const StringData& value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("language_override")); _options.append("language_override", value); return *this; } IndexSpec& IndexSpec::textIndexVersion(int value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("textIndexVersion")); _options.append("textIndexVersion", value); return *this; } IndexSpec& IndexSpec::geo2DSphereIndexVersion(int value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("2dsphereIndexVersion")); _options.append("2dsphereIndexVersion", value); return *this; } IndexSpec& IndexSpec::geo2DBits(int value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("bits")); _options.append("bits", value); return *this; } IndexSpec& IndexSpec::geo2DMin(double value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("min")); _options.append("min", value); return *this; } IndexSpec& IndexSpec::geo2DMax(double value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("max")); _options.append("max", value); return *this; } IndexSpec& IndexSpec::geoHaystackBucketSize(double value) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField("bucketSize")); _options.append("bucketSize", value); return *this; } IndexSpec& IndexSpec::addOption(const BSONElement& option) { uassert(0, kDuplicateOption, !_options.asTempObj().hasField(option.fieldName())); _options.append(option); return *this; } IndexSpec& IndexSpec::addOptions(const BSONObj& options) { BSONObjIterator iter(options); while (iter.more()) addOption(iter.next()); return *this; } std::string IndexSpec::name() const { return _name; } BSONObj IndexSpec::toBSON() const { BSONObjBuilder bob; bob.append("name", name()); bob.append("key", _keys.asTempObj()); bob.appendElements(_options.asTempObj()); return bob.obj(); } void IndexSpec::_rename() { if (!_dynamicName) return; _name = DBClientWithCommands::genIndexName(_keys.asTempObj()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/index_spec.h000066400000000000000000000155041273231111400236430ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" namespace mongo { class StringData; class MONGO_CLIENT_API IndexSpec { public: // An enumeration of symbolic names for index types. enum IndexType { kIndexTypeAscending, kIndexTypeDescending, kIndexTypeText, kIndexTypeGeo2D, kIndexTypeGeoHaystack, kIndexTypeGeo2DSphere, kIndexTypeHashed, }; // The values to be encoded in BSON for each type of index. static const int kIndexValAscending = 1; static const int kIndexValDescending = -1; static const char kIndexValText[]; static const char kIndexValGeo2D[]; static const char kIndexValGeoHaystack[]; static const char kIndexValGeo2DSphere[]; static const char kIndexValHashed[]; /** Create a new IndexSpec. */ IndexSpec(); // // Methods for adding keys. Methods on this class will prevent you from adding a given // key multiple times. Constraints on the validity of compound indexes are not enforced // here. // /** Add a new component, by default ascending, field to index. */ IndexSpec& addKey(const StringData& field, IndexType type = kIndexTypeAscending); /** Add a component to this index. The field name of the element is used as the field * name to index. The value of the element is the index type. This method exists to * accomodate building future index types for which the enumeration value has not yet * been extended. */ IndexSpec& addKey(const BSONElement& fieldAndType); /** Add all components in the provided key vector to the index descriptor. */ typedef std::vector > KeyVector; IndexSpec& addKeys(const KeyVector& keys); /** Add all keys from the provided object to the index descriptor. */ IndexSpec& addKeys(const BSONObj& keys); // // Methods for adding options. As for keys, duplicated settings are checked and will // raise an error. // // // Common index options // /** Controls whether this index should be built in the foreground or background. By * default indexes are built in the foreground. */ IndexSpec& background(bool value = true); /** Set whether or not this index should enforce uniqueness. By default, uniqueness is * not enforced. */ IndexSpec& unique(bool value = true); /** Set the name for this index. If not set, a name will be automatically generated. */ IndexSpec& name(const StringData& name); /** Sets whether duplicates detected while indexing should be dropped. By default, * duplicates are not dropped. */ MONGO_CLIENT_DEPRECATED("deprecated in MongoDB 2.8") IndexSpec& dropDuplicates(bool value = true); /** Same as above, but doesn't emit a compiler warning on use. */ IndexSpec& dropDuplicatesDeprecated(bool value = true); /** Sets whether or not this index should be sparse. By default, indexes are not * sparse. */ IndexSpec& sparse(bool value = true); /** Enables time-to-live semantics for this index with the specified lifetime in * seconds. Note that the indexed field must be of type UTC datetime for this option * to work correctly. */ IndexSpec& expireAfterSeconds(int value); /** Explicitly request an index of the given version. As of MongoDB 2.6, the only accepted * values are 0 or 1. Versions 2.0 and later default to '1'. Do not set this option except * in unusual circumstances. */ IndexSpec& version(int value); /** Sets the 'partialFilterExpression' document for a partial index. */ IndexSpec& partialFilterExpression(const BSONObj& value); // // Text options // /** Sets the 'weights' document for a text index. */ IndexSpec& textWeights(const BSONObj& value); /** Sets the default language for a text index. */ IndexSpec& textDefaultLanguage(const StringData& value); /** Sets the name of the field containing the language override in a text index. */ IndexSpec& textLanguageOverride(const StringData& value); /** Sets the version of the text index to use. MongoDB 2.4 only supports version * '1'. If not otherwise specified, MongoDB 2.6 defaults to version 2. */ IndexSpec& textIndexVersion(int value); // // 2D Sphere Options // /** Sets the version of the 2D sphere index to use. MongoDB 2.4 only supports version * '1'. If not otherwise specified, MongoDB 2.6 defaults to version 2. */ IndexSpec& geo2DSphereIndexVersion(int value); // // Geo2D Options // /** Sets the number of bits of precision for geohash. */ IndexSpec& geo2DBits(int value); /** Sets the minimum value for keys in a geo2d index. */ IndexSpec& geo2DMin(double value); /** Sets the maximum value for keys in a geo2d index. */ IndexSpec& geo2DMax(double value); // // Geo Haystack Options // /** Sets the bucket size for haystack indexes. */ IndexSpec& geoHaystackBucketSize(double value); // // Support for adding generic options. This is here so that if new index options // become available on the server those options can be set independently of the // named methods above. // /** Adds another option verbatim. */ IndexSpec& addOption(const BSONElement& option); /** Adds the provided options verbatim. */ IndexSpec& addOptions(const BSONObj& options); /** Get a copy of the current name for this index. If a name was provided to the * constructor, a copy of this name is returned. Otherwise, the current auto-generated * name given the set of indexes will be returned. Note that this is a copy: * subsequent changes to the indexed fields will not affect the value returned here, * and you must call 'name' again to obtain the updated value. */ std::string name() const; /** Return a BSONObj that captures the selected index keys and options. */ BSONObj toBSON() const; private: void _rename(); std::string _name; bool _dynamicName; mutable BSONObjBuilder _keys; mutable BSONObjBuilder _options; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/index_spec_test.cpp000066400000000000000000000057551273231111400252440ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/index_spec.h" #include "mongo/unittest/unittest.h" #define ASSERT_UASSERTS(STATEMENT) ASSERT_THROWS(STATEMENT, UserException) namespace mongo { TEST(Options, RepeatedOptionsFail) { ASSERT_UASSERTS(IndexSpec().background().background()); ASSERT_UASSERTS(IndexSpec().unique().unique()); ASSERT_UASSERTS(IndexSpec().dropDuplicatesDeprecated().dropDuplicatesDeprecated()); ASSERT_UASSERTS(IndexSpec().sparse().sparse()); ASSERT_UASSERTS(IndexSpec().expireAfterSeconds(1).expireAfterSeconds(1)); ASSERT_UASSERTS(IndexSpec().version(0).version(0)); ASSERT_UASSERTS( IndexSpec().partialFilterExpression(BSONObj()).partialFilterExpression(BSONObj())); ASSERT_UASSERTS(IndexSpec().textWeights(BSONObj()).textWeights(BSONObj())); ASSERT_UASSERTS(IndexSpec().textDefaultLanguage("foo").textDefaultLanguage("foo")); ASSERT_UASSERTS(IndexSpec().textLanguageOverride("foo").textLanguageOverride("foo")); ASSERT_UASSERTS(IndexSpec().textIndexVersion(0).textIndexVersion(0)); ASSERT_UASSERTS(IndexSpec().geo2DSphereIndexVersion(0).geo2DSphereIndexVersion(0)); ASSERT_UASSERTS(IndexSpec().geo2DBits(0).geo2DBits(0)); ASSERT_UASSERTS(IndexSpec().geo2DMin(2.00).geo2DMin(2.00)); ASSERT_UASSERTS(IndexSpec().geo2DMax(2.00).geo2DMax(2.00)); ASSERT_UASSERTS(IndexSpec().geoHaystackBucketSize(2.0).geoHaystackBucketSize(2.0)); ASSERT_UASSERTS(IndexSpec().addOptions(BSON("foo" << 1 << "foo" << 1))); ASSERT_UASSERTS(IndexSpec().sparse(0).addOptions(BSON("sparse" << 1))); } TEST(Options, RepeatedKeysFail) { IndexSpec spec; spec.addKey("aField"); ASSERT_UASSERTS(spec.addKey("aField")); const BSONObj fields = BSON("someField" << 1 << "aField" << 1 << "anotherField" << 1); ASSERT_UASSERTS(spec.addKey(fields.getField("aField"))); ASSERT_UASSERTS(spec.addKeys(fields)); } TEST(Options, NameIsHonored) { IndexSpec spec; spec.addKey("aField"); // Should get an auto generated name ASSERT_FALSE(spec.name().empty()); // That is not the name we are about to set. ASSERT_NE("someName", spec.name()); spec.name("someName"); // Should get the name we specified. ASSERT_EQ("someName", spec.name()); // Name can be changed as many times as we want spec.name("yetAnotherName"); ASSERT_EQ("yetAnotherName", spec.name()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/init.cpp000066400000000000000000000112131273231111400230110ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault; #include "mongo/platform/basic.h" #include "mongo/client/init.h" #include #include "mongo/base/initializer.h" #include "mongo/client/private/options.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/platform/atomic_word.h" #include "mongo/stdx/functional.h" #include "mongo/util/background.h" #include "mongo/util/log.h" #include "mongo/util/net/sock.h" namespace mongo { namespace client { namespace { // 0 = not yet initialized // 1 = initialized, not yet shut down // -1 = terminated AtomicWord isInitialized; void callShutdownAtExit() { // We can't really do anything if this returns a non-OK status. mongo::client::shutdown(); } void configureLogging(const Options& opts) { const mongo::client::Options::LogAppenderFactory& appenderFactory = opts.logAppenderFactory(); if (appenderFactory) { logger::ComponentMessageLogDomain* globalLogDomain = logger::globalLogManager()->getGlobalDomain(); globalLogDomain->attachAppender(appenderFactory()); globalLogDomain->setMinimumLoggedSeverity(opts.minLoggedSeverity()); } } } // namespace Status initialize(const Options& options) { int initStatus = isInitialized.compareAndSwap(0, 1); if (initStatus == 0) { // Copy in the provided options. setOptions(options); configureLogging(options); #if defined(_WIN32) && !defined(STATIC_LIBMONGOCLIENT) if (options.callShutdownAtExit()) { return Status( ErrorCodes::IllegalOperation, "The DLL build of the MongoDB C++ driver does not support shutdown at exit"); } #endif if (options.callShutdownAtExit()) { if (std::atexit(&callShutdownAtExit) != 0) { return Status(ErrorCodes::InternalError, "Failed setting client driver atexit shutdown handler"); } } enableIPv6(options.IPv6Enabled()); Status result = runGlobalInitializers(0, NULL, NULL); if (!result.isOK()) return result; result = ReplicaSetMonitor::initialize(); if (!result.isOK()) { return result; } return Status::OK(); } else if (initStatus == 1) { return Status(ErrorCodes::AlreadyInitialized, "Initialize() may only be called once"); } else { return Status(ErrorCodes::IllegalOperation, "The driver has been terminated."); } } Status shutdown() { int initStatus = isInitialized.compareAndSwap(1, -1); if (initStatus == 1) { Status result = ReplicaSetMonitor::shutdown(Options::current().autoShutdownGracePeriodMillis()); if (!result.isOK()) { if (result == ErrorCodes::ExceededTimeLimit) { return result; } warning() << "The ReplicaSetMonitor was shutdown prior to driver termination. " << "This is a non-fatal error that can occur if you are calling " << "ReplicaSetMonitor::shutdown() manually." << std::endl; } shutdownNetworking(); return Status::OK(); } else if (initStatus == 0) { return Status( ErrorCodes::IllegalOperation, "mongo::client::shutdown() cannot be called before mongo::client::initialize()"); } else { return Status(ErrorCodes::IllegalOperation, "The driver has been terminated."); } } GlobalInstance::GlobalInstance(const Options& options) : _terminateNeeded(false), _status(initialize(options)) { if (initialized()) _terminateNeeded = !Options::current().callShutdownAtExit(); } GlobalInstance::~GlobalInstance() { if (_terminateNeeded && !client::shutdown().isOK()) std::abort(); } void GlobalInstance::assertInitialized() const { uassertStatusOK(status()); } Status GlobalInstance::shutdown() { const Status result = client::shutdown(); if (result.isOK()) _terminateNeeded = false; return result; } } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/init.h000066400000000000000000000112201273231111400224540ustar00rootroot00000000000000// @file init.h /* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" #include "mongo/client/export_macros.h" #include "mongo/client/options.h" // NOTE: These functions are only intended to be used when linking against the libmongoclient // library. The below functions are not defined in servers like mongos or mongod, which have // their own initialization strategy. /** * @namespace mongo * @brief the main MongoDB namespace */ namespace mongo { /** * @namespace mongo::client * @brief the MongoDB C++ driver namespace */ namespace client { /** * Initializes the client driver, possibly with custom options. See the Options class for * details on the various fields. * * initialize() MUST be called EXACTLY once after entering 'main' and before using * the driver. Do not call initialize() before entering 'main' * (i.e. from a static initializer), as it relies on all static initialization * having been completed. */ MONGO_CLIENT_API Status MONGO_CLIENT_FUNC initialize(const Options& options = Options()); /** * Terminates the client driver. If the driver does not terminate within the currently * configured grace period in the driver options, an 'ExceededTimeLimit' Status will be * returned, in which case it is legal to retry 'shutdown'. Other non-OK status values do * not admit retrying the operation. A permanent failure to terminate the driver should be * logged, and it may be unsafe to exit the process by any mechanism which causes normal * destruction of static objects. * * Once the driver has been terminated, it cannot be initialized again. */ MONGO_CLIENT_API Status MONGO_CLIENT_FUNC shutdown(); /** An RAII helper to simplify driver setup and teardown. If more refined control over * error handling of initialization and shutdown is required, use the explicit * 'initialize' and 'shutdown' functions above. Note that the restrictions on the * invocation of 'initialize' are not obviated by using this class. Please see the methods * below for more details. */ class MONGO_CLIENT_API GlobalInstance { MONGO_DISALLOW_COPYING(GlobalInstance); public: /** Invokes 'mongo::client::initialize" with the provided Options, or the default * Options if none are provided. If initialization is successful, destruction of the * GlobalInstance will invoke 'shutdown' if such a call would not otherwise * automatically be performed by the library via atexit (see * Options::setCallShutdownAtExit). After constructing the GlobalInstance, you must * check whether the initialization was successful via the 'initialized' method, or by * checking the Status object returned by the 'status' member function. A failed * GLobalInstance will not attempt to invoke shutdown. */ explicit GlobalInstance(const Options& options = Options()); /** Invokes 'mongo::client::shutdown' if the GlobalInstance succeeded in initializing * the library and if the options used to successfully initialize the driver will not * automatically result in a call to 'mongo::client::shutdown' during atexit * processing. */ ~GlobalInstance(); /** Returns the Status generated by the internal call to 'client::initialize'. */ const Status& status() const { return _status; } /** Returns 'true' if initialization succeeded, 'false' otherwise. */ bool initialized() const { return status().isOK(); } /** Raises a UserAssertion exception if the GlobalInstance failed to initialize the * library. */ void assertInitialized() const; /** Immediately calls 'shutdown' on the driver and returns the resulting Status. If the * returned Status is OK, then the GlobalInstance will abandon the pending call to * 'shutdown' from its destructor. If the returned Status is not an OK status, then * the pending call to 'shutdown' is not canceled. The call to * GlobalInstance::shutdown may be retried if it returns a non-OK Status. */ Status shutdown(); private: bool _terminateNeeded; const Status _status; }; } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/insert_write_operation.cpp000066400000000000000000000047011273231111400266500ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/insert_write_operation.h" #include "mongo/bson/bsontypes.h" #include "mongo/client/dbclientinterface.h" #include "mongo/db/namespace_string.h" namespace mongo { namespace { const char kCommandKey[] = "insert"; const char kBatchName[] = "documents"; } // namespace InsertWriteOperation::InsertWriteOperation(const BSONObj& doc) : _doc(_ensureId(doc)) {} WriteOpType InsertWriteOperation::operationType() const { return dbWriteInsert; } const char* InsertWriteOperation::batchName() const { return kBatchName; } int InsertWriteOperation::incrementalSize() const { return _doc.objsize(); } void InsertWriteOperation::startRequest(const std::string& ns, bool ordered, BufBuilder* builder) const { builder->appendNum(ordered ? 0 : 1); builder->appendStr(ns); } void InsertWriteOperation::appendSelfToRequest(BufBuilder* builder) const { _doc.appendSelfToBufBuilder(*builder); } void InsertWriteOperation::startCommand(const std::string& ns, BSONObjBuilder* command) const { command->append(kCommandKey, nsToCollectionSubstring(ns)); } void InsertWriteOperation::appendSelfToCommand(BSONArrayBuilder* batch) const { batch->append(_doc); } void InsertWriteOperation::appendSelfToBSONObj(BSONObjBuilder* obj) const { obj->appendElements(_doc); } BSONObj InsertWriteOperation::_ensureId(const BSONObj& doc) { BSONElement id = doc.getField("_id"); if (!id.eoo()) { uassert(0, "value of _id element cannot contain any fields starting with $", !id.isABSONObj() || id.Obj().okForStorage()); return doc; } BSONObjBuilder bob; bob.append("_id", OID::gen()); bob.appendElements(doc); return bob.obj(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/insert_write_operation.h000066400000000000000000000026461273231111400263230ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/write_operation_base.h" namespace mongo { class InsertWriteOperation : public WriteOperationBase { public: explicit InsertWriteOperation(const BSONObj& doc); virtual WriteOpType operationType() const; virtual const char* batchName() const; virtual int incrementalSize() const; virtual void startRequest(const std::string& ns, bool ordered, BufBuilder* builder) const; virtual void appendSelfToRequest(BufBuilder* builder) const; virtual void startCommand(const std::string& ns, BSONObjBuilder* command) const; virtual void appendSelfToCommand(BSONArrayBuilder* batch) const; virtual void appendSelfToBSONObj(BSONObjBuilder* obj) const; private: static BSONObj _ensureId(const BSONObj& doc); const BSONObj _doc; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/insert_write_operation_test.cpp000066400000000000000000000031641273231111400277110ustar00rootroot00000000000000/* Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/insert_write_operation.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/util/assert_util.h" #include "mongo/unittest/unittest.h" namespace { using namespace mongo; TEST(InsertWriteOperation, IdFieldCannotContainDollarSignTopLevel) { BSONObjBuilder bob; bob.append("foo", "bar"); BSONObjBuilder subbob(bob.subobjStart("_id")); subbob.append("$bad", "nogood"); subbob.done(); ASSERT_THROWS(InsertWriteOperation w(bob.done()), UserException); } TEST(InsertWriteOperation, IdFieldCannotContainDollarSignNested) { BSONObjBuilder bob; bob.append("garply", "nnnnoooo"); BSONObjBuilder subbob(bob.subobjStart("_id")); BSONObjBuilder subsubbob(subbob.subobjStart("foo")); BSONObjBuilder subsubsubbob(subbob.subobjStart("baz")); subsubsubbob.append("$blah", "borked"); subsubsubbob.done(); subsubbob.done(); subbob.done(); ASSERT_THROWS(InsertWriteOperation w(bob.done()), UserException); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/client/native_sasl_client_session.cpp000066400000000000000000000053621273231111400274670ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/native_sasl_client_session.h" #include "mongo/base/init.h" #include "mongo/client/sasl_client_conversation.h" #include "mongo/client/sasl_plain_client_conversation.h" #include "mongo/client/sasl_scramsha1_client_conversation.h" #include "mongo/util/mongoutils/str.h" namespace mongo { namespace { SaslClientSession* createNativeSaslClientSession(const std::string mech) { return new NativeSaslClientSession(); } MONGO_INITIALIZER(NativeSaslClientContext)(InitializerContext* context) { SaslClientSession::create = createNativeSaslClientSession; return Status::OK(); } } // namespace NativeSaslClientSession::NativeSaslClientSession() : SaslClientSession(), _step(0), _done(false), _saslConversation(NULL) {} NativeSaslClientSession::~NativeSaslClientSession() {} Status NativeSaslClientSession::initialize() { if (_saslConversation) return Status(ErrorCodes::AlreadyInitialized, "Cannot reinitialize NativeSaslClientSession."); std::string mechanism = getParameter(parameterMechanism).toString(); if (mechanism == "PLAIN") { _saslConversation.reset(new SaslPLAINClientConversation(this)); } else if (mechanism == "SCRAM-SHA-1") { _saslConversation.reset(new SaslSCRAMSHA1ClientConversation(this)); } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "SASL mechanism " << mechanism << " is not supported"); } return Status::OK(); } Status NativeSaslClientSession::step(const StringData& inputData, std::string* outputData) { if (!_saslConversation) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "The client authentication session has not been properly initialized"); } StatusWith status = _saslConversation->step(inputData, outputData); if (status.isOK()) { _done = status.getValue(); } return status.getStatus(); } } // namespace MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(client_native_sasl_client_session) mongo-cxx-driver-legacy-1.1.2/src/mongo/client/native_sasl_client_session.h000066400000000000000000000027531273231111400271350ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongo/client/sasl_client_session.h" namespace mongo { class SaslClientConversation; /** * Implementation of the client side of a SASL authentication conversation using the * native SASL implementation. */ class NativeSaslClientSession : public SaslClientSession { MONGO_DISALLOW_COPYING(NativeSaslClientSession); public: NativeSaslClientSession(); ~NativeSaslClientSession(); virtual Status initialize(); virtual Status step(const StringData& inputData, std::string* outputData); virtual bool isDone() const { return _done; } private: /// Number of successfully completed conversation steps. int _step; /// See isDone(). bool _done; /// The client side of a SASL authentication conversation. boost::scoped_ptr _saslConversation; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/options.cpp000066400000000000000000000121621273231111400235450ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault; #include "mongo/platform/basic.h" #include "mongo/client/private/options.h" #include "mongo/client/options.h" #include "mongo/util/log.h" namespace mongo { namespace client { namespace { // The unique global options instance. Options options; } // namespace #if !defined(_MSC_EXTENSIONS) const int Options::kDefaultDefaultLocalThresholdMillis; const unsigned int Options::kDefaultAutoShutdownGracePeriodMillis; #endif void setOptions(const Options& newOptions) { options = newOptions; } const Options& Options::current() { return options; } Options::Options() : _callShutdownAtExit(false), _autoShutdownGracePeriodMillis(kDefaultAutoShutdownGracePeriodMillis), _sslMode(kSSLDisabled), _useFIPSMode(false), _sslAllowInvalidCertificates(false), _sslAllowInvalidHostnames(false), _defaultLocalThresholdMillis(kDefaultDefaultLocalThresholdMillis), _minLoggedSeverity(logger::LogSeverity::Log()), _IPv6Enabled(false), _validateObjects(false) {} Options& Options::setCallShutdownAtExit(bool value) { _callShutdownAtExit = value; return *this; } bool Options::callShutdownAtExit() const { return _callShutdownAtExit; } Options& Options::setAutoShutdownGracePeriodMillis(unsigned int millis) { _autoShutdownGracePeriodMillis = millis; return *this; } unsigned int Options::autoShutdownGracePeriodMillis() const { return _autoShutdownGracePeriodMillis; } Options& Options::setDefaultLocalThresholdMillis(int millis) { _defaultLocalThresholdMillis = millis; return *this; } int Options::defaultLocalThresholdMillis() const { return _defaultLocalThresholdMillis; } Options& Options::setSSLMode(SSLModes sslMode) { _sslMode = sslMode; return *this; } Options::SSLModes Options::SSLMode() const { return _sslMode; } Options& Options::setFIPSMode(bool value) { _useFIPSMode = value; return *this; } const bool Options::FIPSMode() const { return _useFIPSMode; } Options& Options::setSSLDisabledTLSProtocols(const std::vector& protocols) { _sslDisabledTLSProtocols = protocols; return *this; } const std::vector& Options::SSLDisabledTLSProtocols() const { return _sslDisabledTLSProtocols; } Options& Options::setSSLCAFile(const std::string& fileName) { _sslCAFile = fileName; return *this; } const std::string& Options::SSLCAFile() const { return _sslCAFile; } Options& Options::setSSLPEMKeyFile(const std::string& fileName) { _sslPEMKeyFile = fileName; return *this; } const std::string& Options::SSLPEMKeyFile() const { return _sslPEMKeyFile; } Options& Options::setSSLPEMKeyPassword(const std::string& password) { _sslPEMKeyPassword = password; return *this; } const std::string& Options::SSLPEMKeyPassword() const { return _sslPEMKeyPassword; } Options& Options::setSSLCRLFile(const std::string& fileName) { _sslCRLFile = fileName; return *this; } const std::string& Options::SSLCRLFile() const { return _sslCRLFile; } Options& Options::setSSLAllowInvalidCertificates(bool value) { _sslAllowInvalidCertificates = value; return *this; } const bool Options::SSLAllowInvalidCertificates() const { return _sslAllowInvalidCertificates; } Options& Options::setSSLAllowInvalidHostnames(bool value) { _sslAllowInvalidHostnames = value; return *this; } const bool Options::SSLAllowInvalidHostnames() const { return _sslAllowInvalidHostnames; } Options& Options::setSSLCipherConfig(const std::string& config) { _sslCipherConfig = config; return *this; } const std::string& Options::SSLCipherConfig() const { return _sslCipherConfig; } Options& Options::setLogAppenderFactory(const Options::LogAppenderFactory& factory) { _appenderFactory = factory; return *this; } const Options::LogAppenderFactory& Options::logAppenderFactory() const { return _appenderFactory; } Options& Options::setMinLoggedSeverity(logger::LogSeverity level) { _minLoggedSeverity = level; return *this; } logger::LogSeverity Options::minLoggedSeverity() const { return _minLoggedSeverity; } Options& Options::setIPv6Enabled(bool state) { _IPv6Enabled = state; return *this; } bool Options::IPv6Enabled() const { return _IPv6Enabled; } Options& Options::setValidateObjects(bool value) { _validateObjects = value; return *this; } bool Options::validateObjects() const { return _validateObjects; } } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/options.h000066400000000000000000000202161273231111400232110ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/client/export_macros.h" #include "mongo/logger/log_domain.h" #include "mongo/logger/message_log_domain.h" #include "mongo/stdx/functional.h" namespace mongo { namespace client { /** The Options structure is passed to mongo::client::initialize to configure various * properties and configurations of the driver. */ class MONGO_CLIENT_API Options { public: // Defaults for non-boolean or std::string parameters that are not defaulted to the // empty string. These are useful in case you which to set a parameter to a scale // factor or mutation of the default. static const unsigned int kDefaultAutoShutdownGracePeriodMillis = 0; static const int kDefaultDefaultLocalThresholdMillis = 15; // Helpful typedefs for logging-related options typedef std::auto_ptr LogAppenderPtr; typedef stdx::function LogAppenderFactory; /** Obtains the currently configured options for the driver. This method * must not be called before mongo::client::initialize has completed. */ static const Options& current(); /** Constructs a default options object with default values for all options. The * default option values are documented with each mutator. */ Options(); /** The default ports where different mongodb servers tend to run */ enum DefaultPorts { kDbServer = 27017, kShardServer = 27018, kConfigServer = 27019 }; /** The possible modes for SSL support in an SSL enabled build of the driver. */ enum SSLModes { /** Don't attempt to make SSL connections, or require SSL support of the server. */ kSSLDisabled, /** Attempt SSL connections, but fall back to no SSL if server does not support. * * NOTE: The driver does not currently offer this mode. */ // kSSLPreferred, /** Require SLL. */ kSSLRequired }; /** The TLS protocols */ enum TLSProtocol { kTLS1_0, kTLS1_1, kTLS1_2 }; // // Startup and shutdown // /** If true, the driver will automatically schedule a client::shutdown via * 'std::atexit'. If false, the user of the library is responsible for calling * 'client::shutdown'. Not all platforms support this option (notably, the Windows DLL * build of the driver does not), so the default value of this parameter is * 'false'. If this parameter is set to 'true' and the platform cannot honor the * request to enable 'atexit' termination, 'mongo::client::initialize' will return a * non-OK status. * * Default: false */ Options& setCallShutdownAtExit(bool value = true); bool callShutdownAtExit() const; /** The grace period used when calling client::shutdown from atexit. If * 'callShutdownAtExit' is false, this parameter has no effect. * * Default: 0 ms (wait forever). */ Options& setAutoShutdownGracePeriodMillis(unsigned int millis); unsigned int autoShutdownGracePeriodMillis() const; // // Replication // /** Set the default threshold to consider a node local. * * Default: 15 ms */ Options& setDefaultLocalThresholdMillis(int millis); int defaultLocalThresholdMillis() const; // // SSL // // NOTE: None of the below settings have any effect unless the driver // was compiled with SSL support. // // Glossary: // - CA File: certificate authority certificate file // - PEM Key File: SSL certificate file in PEM format // - CRL: certificate revocation list // - FIPS Mode: OpenSSL crypto library FIPS 140-2 mode processing // /** If set to kSSLRequired, the driver will use SSL when connecting. * * Default: kSSLDisabled */ Options& setSSLMode(SSLModes sslMode = kSSLRequired); SSLModes SSLMode() const; /** A convenience: returns true if SSL is not disabled (preferred or required). */ inline bool SSLEnabled() const { return SSLMode() != kSSLDisabled; } /** Sets whether to operate in FIPS mode. * * Default: false */ Options& setFIPSMode(bool value = true); const bool FIPSMode() const; /** Allow disabling particular TLS protocols * * Default: OpenSSL default */ Options& setSSLDisabledTLSProtocols(const std::vector& protocols); const std::vector& SSLDisabledTLSProtocols() const; /** Configure the SSL CA file to use. Has no effect if 'useSSL' is false. * * Default: false */ Options& setSSLCAFile(const std::string& fileName); const std::string& SSLCAFile() const; /** Configure the SSL PEM key file to use. Has no effect if 'useSSL' is false. * * Default: */ Options& setSSLPEMKeyFile(const std::string& fileName); const std::string& SSLPEMKeyFile() const; /** Configure the SSL PEM key password. Has no effect if 'useSSL' is false. * * Default: */ Options& setSSLPEMKeyPassword(const std::string& password); const std::string& SSLPEMKeyPassword() const; /** Configure the SSL CRL file to use. Has no effect if 'useSSL' is false. * * Default: */ Options& setSSLCRLFile(const std::string& fileName); const std::string& SSLCRLFile() const; /** When set true, SSL certificate validation is disabled. * * Default: false */ Options& setSSLAllowInvalidCertificates(bool value = true); const bool SSLAllowInvalidCertificates() const; /** When set true, SSL hostname validation is disabled. * * Default: false */ Options& setSSLAllowInvalidHostnames(bool value = true); const bool SSLAllowInvalidHostnames() const; /** Override the default OpenSSL cipher configuration * * Default: OpenSSL default */ Options& setSSLCipherConfig(const std::string& config); const std::string& SSLCipherConfig() const; // // Logging // /** Provide a factory for a log appender to configure logging. * * Default: no log appender, and logging is not enabled. */ Options& setLogAppenderFactory(const LogAppenderFactory& factory); const LogAppenderFactory& logAppenderFactory() const; /** Specify the minimum severity of messages that will be logged, if logging * is enabled. * * Default: LogSeverity::Log() */ Options& setMinLoggedSeverity(logger::LogSeverity level); logger::LogSeverity minLoggedSeverity() const; // // Networking // /** Enable support for the IPv6 protocol family. * * Default: false */ Options& setIPv6Enabled(bool state); bool IPv6Enabled() const; // // Misc // /** Configure whether BSON objects returned from the server should be validated. * * Default: false */ Options& setValidateObjects(bool value = true); bool validateObjects() const; private: bool _callShutdownAtExit; unsigned int _autoShutdownGracePeriodMillis; SSLModes _sslMode; bool _useFIPSMode; std::vector _sslDisabledTLSProtocols; std::string _sslCAFile; std::string _sslPEMKeyFile; std::string _sslPEMKeyPassword; std::string _sslCRLFile; bool _sslAllowInvalidCertificates; bool _sslAllowInvalidHostnames; std::string _sslCipherConfig; int _defaultLocalThresholdMillis; LogAppenderFactory _appenderFactory; logger::LogSeverity _minLoggedSeverity; bool _IPv6Enabled; bool _validateObjects; }; } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/private/000077500000000000000000000000001273231111400230165ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/client/private/options.h000066400000000000000000000015731273231111400246700ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { namespace client { class Options; // Sets the current global options. It is expected that this will be called from // 'initialize' and nowhere else. void setOptions(const Options& newOptions); } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/redef_macros.h000066400000000000000000000034201273231111400241450ustar00rootroot00000000000000/** @file redef_macros.h macros for mongo internals @see undef_macros.h undefines these after use to minimize name pollution. */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // If you define a new global un-prefixed macro, please add it here and in undef_macros #define MONGO_MACROS_PUSHED 1 #if defined(_WIN32) #pragma push_macro("min") #undef min #pragma push_macro("max") #undef max #pragma push_macro("NOMINMAX") #ifndef NOMINMAX #define NOMINMAX #endif #endif // bson/inline_decls.h #pragma push_macro("NOINLINE_DECL") #undef NOINLINE_DECL #pragma push_macro("PACKED_DECL") #undef PACKED_DECL // util/assert_util.h #pragma push_macro("verify") #undef verify #define verify(expression) MONGO_verify(expression) #pragma push_macro("invariant") #undef invariant #define invariant MONGO_invariant #pragma push_macro("invariantOK") #undef invariantOK #define invariantOK MONGO_invariantOK #pragma push_macro("wassert") #undef wassert #define wassert MONGO_wassert #pragma push_macro("massert") #undef massert #define massert MONGO_massert #pragma push_macro("uassert") #undef uassert #define uassert MONGO_uassert #pragma push_macro("DESTRUCTOR_GUARD") #undef DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD mongo-cxx-driver-legacy-1.1.2/src/mongo/client/replica_set_monitor.cpp000066400000000000000000001241511273231111400261150ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/client/replica_set_monitor.h" #include #include #include #include #include #include #include #include "mongo/client/options.h" #include "mongo/client/private/options.h" #include "mongo/client/replica_set_monitor_internal.h" #include "mongo/util/background.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" #include "mongo/util/string_map.h" #include "mongo/util/timer.h" #if 0 // enable this to ease debugging of this file. #undef DEV #define DEV if (true) #undef LOG #define LOG(x) log() #endif namespace mongo { using std::numeric_limits; using std::string; using std::set; namespace { // Pull nested types to top-level scope typedef ReplicaSetMonitor::IsMasterReply IsMasterReply; typedef ReplicaSetMonitor::ScanState ScanState; typedef ReplicaSetMonitor::ScanStatePtr ScanStatePtr; typedef ReplicaSetMonitor::SetState SetState; typedef ReplicaSetMonitor::SetStatePtr SetStatePtr; typedef ReplicaSetMonitor::Refresher Refresher; typedef Refresher::NextStep NextStep; typedef ScanState::UnconfirmedReplies UnconfirmedReplies; typedef SetState::Node Node; typedef SetState::Nodes Nodes; const double socketTimeoutSecs = 5; /* Replica Set Monitor global state * * watcherLifetimeLock -- mutex held during creation/destruction of * replicaSetMonitorWatcher * replicaSetMonitorWatcher -- background job to check Replica Set members * setsLock -- mutex protecting seedServers and sets * seedServers -- list (map) of servers * sets -- list (map) of ReplicaSetMonitors * * Mutex locking order: * watcherLock should be acquired first when acquiring it and any other lock. * Don't lock setsLock while holding any SetState::mutex. * It is however safe to grab a SetState::mutex without holding setsLock, but * then you can't grab setsLock until you release the SetState::mutex. */ class ReplicaSetMonitorWatcher; boost::mutex watcherLifetimeLock; boost::scoped_ptr replicaSetMonitorWatcher; boost::mutex setsLock; StringMap > seedServers; StringMap sets; // global background job responsible for checking every X amount of time class ReplicaSetMonitorWatcher : public BackgroundJob { public: ReplicaSetMonitorWatcher() : _monitorMutex(), _started(false), _stopRequested(false) {} ~ReplicaSetMonitorWatcher() { stop(); if (running()) { wait(); } } virtual string name() const { return "ReplicaSetMonitorWatcher"; } void safeGo() { boost::lock_guard lk(_monitorMutex); if (_started) return; _started = true; _stopRequested = false; go(); } /** * Stops monitoring the sets and wait for the monitoring thread to terminate. */ void stop() { boost::lock_guard sl(_monitorMutex); _stopRequested = true; _stopRequestedCV.notify_one(); } protected: void run() { log() << "starting"; // includes thread name in output while (true) { { boost::lock_guard sl(_monitorMutex); if (_stopRequested) { break; } } try { checkAllSets(); } catch (std::exception& e) { error() << "check failed: " << e.what(); } catch (...) { error() << "unknown error"; } boost::unique_lock sl(_monitorMutex); if (_stopRequested) { break; } _stopRequestedCV.timed_wait(sl, boost::posix_time::seconds(10)); } } void checkAllSets() { // make a copy so we can quickly unlock setsLock StringMap setsCopy; { boost::lock_guard lk(setsLock); setsCopy = sets; } for (StringMap::const_iterator it = setsCopy.begin(); it != setsCopy.end(); ++it) { LOG(1) << "checking replica set: " << it->first; ReplicaSetMonitorPtr m = it->second; m->startOrContinueRefresh().refreshAll(); const int numFails = m->getConsecutiveFailedScans(); if (numFails >= ReplicaSetMonitor::maxConsecutiveFailedChecks) { log() << "Replica set " << m->getName() << " was down for " << numFails << " checks in a row. Stopping polled monitoring of the set."; // locks setsLock ReplicaSetMonitor::remove(m->getName(), false); } } } // protects _started, _stopRequested boost::mutex _monitorMutex; bool _started; boost::condition_variable _stopRequestedCV; bool _stopRequested; }; // // Helpers for stl algorithms // bool isMaster(const Node& node) { return node.isMaster; } bool compareLatencies(const Node* lhs, const Node* rhs) { // NOTE: this automatically compares Node::unknownLatency worse than all others. return lhs->latencyMicros < rhs->latencyMicros; } bool hostsEqual(const Node& lhs, const HostAndPort& rhs) { return lhs.host == rhs; } // Allows comparing two Nodes, or a HostAndPort and a Node. // NOTE: the two HostAndPort overload is only needed to support extra checks in some STL // implementations. For simplicity, no comparator should be used with collections of just // HostAndPort. struct CompareHosts { bool operator()(const Node& lhs, const Node& rhs) { return lhs.host < rhs.host; } bool operator()(const Node& lhs, const HostAndPort& rhs) { return lhs.host < rhs; } bool operator()(const HostAndPort& lhs, const Node& rhs) { return lhs < rhs.host; } bool operator()(const HostAndPort& lhs, const HostAndPort& rhs) { return lhs < rhs; } } compareHosts; // like an overloaded function, but able to pass to stl algorithms // The following structs should be treated as functions returning a UnaryPredicate. // Usage example: std::find_if(nodes.begin(), nodes.end(), hostIs(someHost)); // They all hold their constructor argument by reference. struct hostIs { explicit hostIs(const HostAndPort& host) : _host(host) {} bool operator()(const HostAndPort& host) { return host == _host; } bool operator()(const Node& node) { return node.host == _host; } const HostAndPort& _host; }; struct hostNotIn { explicit hostNotIn(const std::set& hosts) : _hosts(hosts) {} bool operator()(const HostAndPort& host) { return !_hosts.count(host); } bool operator()(const Node& node) { return !_hosts.count(node.host); } const std::set& _hosts; }; } // namespace // At 1 check every 10 seconds, 30 checks takes 5 minutes int ReplicaSetMonitor::maxConsecutiveFailedChecks = 30; // Defaults to random selection as required by the spec bool ReplicaSetMonitor::useDeterministicHostSelection = false; ReplicaSetMonitor::ReplicaSetMonitor(StringData name, const std::set& seeds) : _state(boost::make_shared(name, seeds)) { LogstreamBuilder lsb = log(); lsb << "starting new replica set monitor for replica set " << name << " with seeds "; for (std::set::const_iterator it = seeds.begin(); it != seeds.end(); ++it) { if (it != seeds.begin()) lsb << ','; lsb << *it; } } HostAndPort ReplicaSetMonitor::getHostOrRefresh(const ReadPreferenceSetting& criteria) { { boost::lock_guard lk(_state->mutex); HostAndPort out = _state->getMatchingHost(criteria); if (!out.empty()) return out; } { Refresher refresher = startOrContinueRefresh(); HostAndPort out = refresher.refreshUntilMatches(criteria); if (!out.empty() || refresher.startedNewScan()) return out; } // We didn't find any matching hosts and the scan we just finished may have stale data from // before we joined. Therefore we should participate in a new scan to make sure all hosts // are contacted at least once (possibly by other threads) before this function gives up. return startOrContinueRefresh().refreshUntilMatches(criteria); } HostAndPort ReplicaSetMonitor::getMasterOrUassert() { const ReadPreferenceSetting masterOnly(ReadPreference_PrimaryOnly, TagSet()); HostAndPort master = getHostOrRefresh(masterOnly); uassert(10009, str::stream() << "ReplicaSetMonitor no master found for set: " << getName(), !master.empty()); return master; } Refresher ReplicaSetMonitor::startOrContinueRefresh() { boost::lock_guard lk(_state->mutex); Refresher out(_state); DEV _state->checkInvariants(); return out; } void ReplicaSetMonitor::failedHost(const HostAndPort& host) { boost::lock_guard lk(_state->mutex); Node* node = _state->findNode(host); if (node) node->markFailed(); DEV _state->checkInvariants(); } bool ReplicaSetMonitor::isPrimary(const HostAndPort& host) const { boost::lock_guard lk(_state->mutex); Node* node = _state->findNode(host); return node ? node->isMaster : false; } bool ReplicaSetMonitor::isHostUp(const HostAndPort& host) const { boost::lock_guard lk(_state->mutex); Node* node = _state->findNode(host); return node ? node->isUp : false; } int ReplicaSetMonitor::getConsecutiveFailedScans() const { boost::lock_guard lk(_state->mutex); return _state->consecutiveFailedScans; } std::string ReplicaSetMonitor::getName() const { // name is const so don't need to lock return _state->name; } std::string ReplicaSetMonitor::getServerAddress() const { boost::lock_guard lk(_state->mutex); return _state->getServerAddress(); } bool ReplicaSetMonitor::contains(const HostAndPort& host) const { boost::lock_guard lk(_state->mutex); return _state->seedNodes.count(host); } void ReplicaSetMonitor::createIfNeeded(const string& name, const set& servers) { LOG(3) << "ReplicaSetMonitor::createIfNeeded " << name; boost::lock_guard lk(setsLock); ReplicaSetMonitorPtr& m = sets[name]; if (!m) m = boost::make_shared(name, servers); // Don't need to hold the lifetime lock for safeGo as // 1) we assume the monitor is created as the contract of this class is such that initialize() // must have been called. // 2) replicaSetMonitorWatcher synchronizes safeGo internally using the _monitorMutex replicaSetMonitorWatcher->safeGo(); } ReplicaSetMonitorPtr ReplicaSetMonitor::get(const string& name, const bool createFromSeed) { LOG(3) << "ReplicaSetMonitor::get " << name; boost::lock_guard lk(setsLock); StringMap::const_iterator i = sets.find(name); if (i != sets.end()) { return i->second; } if (createFromSeed) { StringMap >::const_iterator j = seedServers.find(name); if (j != seedServers.end()) { LOG(4) << "Creating ReplicaSetMonitor from cached address"; ReplicaSetMonitorPtr& m = sets[name]; invariant(!m); m.reset(new ReplicaSetMonitor(name, j->second)); // see above comment in createIfNeeded for why we don't need the // watcherLifetimeLock replicaSetMonitorWatcher->safeGo(); return m; } } return ReplicaSetMonitorPtr(); } set ReplicaSetMonitor::getAllTrackedSets() { set activeSets; boost::lock_guard lk(setsLock); for (StringMap::const_iterator it = sets.begin(); it != sets.end(); ++it) { activeSets.insert(it->first); } return activeSets; } void ReplicaSetMonitor::remove(const string& name, bool clearSeedCache) { LOG(2) << "Removing ReplicaSetMonitor for " << name << " from replica set table" << (clearSeedCache ? " and the seed cache" : ""); boost::lock_guard lk(setsLock); const StringMap::const_iterator setIt = sets.find(name); if (setIt != sets.end()) { if (!clearSeedCache) { // Save list of current set members so that the monitor can be rebuilt if needed. const ReplicaSetMonitorPtr& rsm = setIt->second; boost::lock_guard lk(rsm->_state->mutex); seedServers[name] = rsm->_state->seedNodes; } sets.erase(setIt); } if (clearSeedCache) { seedServers.erase(name); } } void ReplicaSetMonitor::setConfigChangeHook(ConfigChangeHook hook) { massert(13610, "ConfigChangeHook already specified", !SetState::configChangeHook); SetState::configChangeHook = hook; } // TODO move to correct order with non-statics before pushing void ReplicaSetMonitor::appendInfo(BSONObjBuilder& bsonObjBuilder) const { boost::lock_guard lk(_state->mutex); // NOTE: the format here must be consistent for backwards compatibility BSONArrayBuilder hosts(bsonObjBuilder.subarrayStart("hosts")); for (unsigned i = 0; i < _state->nodes.size(); i++) { const Node& node = _state->nodes[i]; BSONObjBuilder builder; builder.append("addr", node.host.toString()); builder.append("ok", node.isUp); builder.append("ismaster", node.isMaster); // intentionally not camelCase builder.append("hidden", false); // we don't keep hidden nodes in the set builder.append("secondary", node.isUp && !node.isMaster); int32_t pingTimeMillis = 0; if (node.latencyMicros / 1000 > numeric_limits::max()) { // In particular, Node::unknownLatency does not fit in an int32. pingTimeMillis = numeric_limits::max(); } else { pingTimeMillis = node.latencyMicros / 1000; } builder.append("pingTimeMillis", pingTimeMillis); if (!node.tags.isEmpty()) { builder.append("tags", node.tags); } hosts.append(builder.obj()); } hosts.done(); } // Users shouldn't need to call this more than once, but our tests do. // Note that this doesn't actually start the watcher, it just creates it. // The watcher is lazily started when we start monitoring our first replica // set, so we don't have to pay the cost of the extra thread unless needed. Status ReplicaSetMonitor::initialize() { boost::lock_guard lock(watcherLifetimeLock); if (replicaSetMonitorWatcher) { return Status(ErrorCodes::AlreadyInitialized, "ReplicaSetMonitorWatcher has already been initialized"); } replicaSetMonitorWatcher.reset(new ReplicaSetMonitorWatcher()); return Status::OK(); } Status ReplicaSetMonitor::shutdown(int gracePeriodMillis) { boost::lock_guard lock(watcherLifetimeLock); if (!replicaSetMonitorWatcher) { return Status(ErrorCodes::InternalError, "ReplicaSetMonitorWatcher has not been initialized"); } // Call cancel first, in case the RSMW was never started. replicaSetMonitorWatcher->cancel(); replicaSetMonitorWatcher->stop(); bool success = replicaSetMonitorWatcher->wait(gracePeriodMillis); if (!success) { return Status(ErrorCodes::ExceededTimeLimit, "Timed out waiting for ReplicaSetMonitorWatcher to shutdown"); } replicaSetMonitorWatcher.reset(); boost::lock_guard lockSets(setsLock); sets = StringMap(); seedServers = StringMap >(); return Status::OK(); } bool ReplicaSetMonitor::isKnownToHaveGoodPrimary() const { boost::mutex::scoped_lock lk(_state->mutex); std::vector::const_iterator where = _state->nodes.begin(); const std::vector::const_iterator end = _state->nodes.end(); for (; where != end; ++where) { if (where->isMaster) { return true; } } return false; } Refresher::Refresher(const SetStatePtr& setState) : _set(setState), _scan(setState->currentScan), _startedNewScan(false) { if (_scan) return; // participate in in-progress scan LOG(2) << "Starting new refresh of replica set " << _set->name; _scan = startNewScan(_set.get()); _set->currentScan = _scan; _startedNewScan = true; } Refresher::NextStep Refresher::getNextStep() { if (_scan != _set->currentScan) return NextStep(NextStep::DONE); // No longer the current scan. // Wait for all dispatched hosts to return before trying any fallback hosts. if (_scan->hostsToScan.empty() && !_scan->waitingFor.empty()) return NextStep(NextStep::WAIT); // If we haven't yet found a master, try contacting unconfirmed hosts if (_scan->hostsToScan.empty() && !_scan->foundUpMaster) { _scan->enqueAllUntriedHosts(_scan->possibleNodes, _set->rand); _scan->possibleNodes.clear(); } if (_scan->hostsToScan.empty()) { // We've tried all hosts we can, so nothing more to do in this round. if (!_scan->foundUpMaster) { warning() << "No primary detected for set " << _set->name; // Since we've talked to everyone we could but still didn't find a primary, we // do the best we can, and assume all unconfirmedReplies are actually from nodes // in the set (we've already confirmed that they think they are). This is // important since it allows us to bootstrap to a usable state even if we are // unable to talk to a master while starting up. As soon as we are able to // contact a master, we will remove any nodes that it doesn't think are part of // the set, undoing the damage we cause here. // NOTE: we don't modify seedNodes or notify about set membership change in this // case since it hasn't been confirmed by a master. for (UnconfirmedReplies::iterator it = _scan->unconfirmedReplies.begin(); it != _scan->unconfirmedReplies.end(); ++it) { _set->findOrCreateNode(it->host)->update(*it); } } if (_scan->foundAnyUpNodes) { _set->consecutiveFailedScans = 0; } else { _set->consecutiveFailedScans++; log() << "All nodes for set " << _set->name << " are down. " << "This has happened for " << _set->consecutiveFailedScans << " checks in a row. Polling will stop after " << maxConsecutiveFailedChecks - _set->consecutiveFailedScans << " more failed checks"; } _set->currentScan.reset(); // Makes sure all other Refreshers in this round return DONE return NextStep(NextStep::DONE); } // Pop and return the next hostToScan. HostAndPort host = _scan->hostsToScan.front(); _scan->hostsToScan.pop_front(); _scan->waitingFor.insert(host); _scan->triedHosts.insert(host); return NextStep(NextStep::CONTACT_HOST, host); } void Refresher::receivedIsMaster(const HostAndPort& from, int64_t latencyMicros, const BSONObj& replyObj) { // Be careful: all return paths must call either failedHost or cv.notify_all! _scan->waitingFor.erase(from); const IsMasterReply reply(from, latencyMicros, replyObj); // Handle various failure cases if (!reply.ok) { failedHost(from); return; } if (reply.setName != _set->name) { warning() << "node: " << from << " isn't a part of set: " << _set->name << " ismaster: " << replyObj; failedHost(from); return; } if (reply.isMaster) { const bool stalePrimary = !receivedIsMasterFromMaster(reply); if (stalePrimary) { log() << "node " << from << " believes it is primary, but its election id of " << reply.electionId << " is older than the most recent election id" << " for this set, " << _set->maxElectionId; failedHost(from); return; } } if (_scan->foundUpMaster) { // We only update a Node if a master has confirmed it is in the set. _set->updateNodeIfInNodes(reply); } else { receivedIsMasterBeforeFoundMaster(reply); _scan->unconfirmedReplies.push_back(reply); } // _set->nodes may still not have any nodes with isUp==true, but we have at least found a // connectible host that is that claims to be in the set. _scan->foundAnyUpNodes = true; // TODO consider only notifying if we've updated a node or we've emptied waitingFor. _set->cv.notify_all(); DEV _set->checkInvariants(); } void Refresher::failedHost(const HostAndPort& host) { _scan->waitingFor.erase(host); // Failed hosts can't pass criteria, so the only way they'd effect the _refreshUntilMatches // loop is if it was the last host we were waitingFor. if (_scan->waitingFor.empty()) _set->cv.notify_all(); Node* node = _set->findNode(host); if (node) node->markFailed(); } ScanStatePtr Refresher::startNewScan(const SetState* set) { const ScanStatePtr scan = boost::make_shared(); // The heuristics we use in deciding the order to contact hosts are designed to find a // master as quickly as possible. This is because we can't use any hosts we find until // we either get the latest set of members from a master or talk to all possible hosts // without finding a master. // TODO It might make sense to check down nodes first if the last seen master is still // marked as up. int upNodes = 0; for (Nodes::const_iterator it(set->nodes.begin()), end(set->nodes.end()); it != end; ++it) { if (it->isUp) { // scan the nodes we think are up first scan->hostsToScan.push_front(it->host); upNodes++; } else { scan->hostsToScan.push_back(it->host); } } // shuffle the queue, but keep "up" nodes at the front std::random_shuffle(scan->hostsToScan.begin(), scan->hostsToScan.begin() + upNodes, set->rand); std::random_shuffle(scan->hostsToScan.begin() + upNodes, scan->hostsToScan.end(), set->rand); if (!set->lastSeenMaster.empty()) { // move lastSeenMaster to front of queue std::stable_partition( scan->hostsToScan.begin(), scan->hostsToScan.end(), hostIs(set->lastSeenMaster)); } return scan; } bool Refresher::receivedIsMasterFromMaster(const IsMasterReply& reply) { invariant(reply.isMaster); if (reply.electionId.isSet()) { if (_set->maxElectionId.isSet() && _set->maxElectionId.compare(reply.electionId) > 0) { return false; } _set->maxElectionId = reply.electionId; } // Mark all nodes as not master. We will mark ourself as master before releasing the lock. // NOTE: we use a "last-wins" policy if multiple hosts claim to be master. for (size_t i = 0; i < _set->nodes.size(); i++) { _set->nodes[i].isMaster = false; } // Check if the master agrees with our current list of nodes. // REMINDER: both _set->nodes and reply.normalHosts are sorted. if (_set->nodes.size() != reply.normalHosts.size() || !std::equal( _set->nodes.begin(), _set->nodes.end(), reply.normalHosts.begin(), hostsEqual)) { LOG(2) << "Adjusting nodes in our view of replica set " << _set->name << " based on master reply: " << reply.raw; // remove non-members from _set->nodes _set->nodes.erase( std::remove_if(_set->nodes.begin(), _set->nodes.end(), hostNotIn(reply.normalHosts)), _set->nodes.end()); // add new members to _set->nodes for (std::set::const_iterator it = reply.normalHosts.begin(); it != reply.normalHosts.end(); ++it) { _set->findOrCreateNode(*it); } // replace hostToScan queue with untried normal hosts. can both add and remove // hosts from the queue. _scan->hostsToScan.clear(); _scan->enqueAllUntriedHosts(reply.normalHosts, _set->rand); if (!_scan->waitingFor.empty()) { // make sure we don't wait for any hosts that aren't considered members std::set newWaitingFor; std::set_intersection(reply.normalHosts.begin(), reply.normalHosts.end(), _scan->waitingFor.begin(), _scan->waitingFor.end(), std::inserter(newWaitingFor, newWaitingFor.end())); _scan->waitingFor.swap(newWaitingFor); } } if (reply.normalHosts != _set->seedNodes) { const string oldAddr = _set->getServerAddress(); _set->seedNodes = reply.normalHosts; // LogLevel can be pretty low, since replica set reconfiguration should be pretty rare // and we want to record our changes log() << "changing hosts to " << _set->getServerAddress() << " from " << oldAddr; if (SetState::configChangeHook) { // call from a separate thread to avoid blocking and holding lock while potentially // going over the network boost::thread bg(SetState::configChangeHook, _set->name, _set->getServerAddress()); bg.detach(); } } // Update other nodes's information based on replies we've already seen for (UnconfirmedReplies::iterator it = _scan->unconfirmedReplies.begin(); it != _scan->unconfirmedReplies.end(); ++it) { // this ignores replies from hosts not in _set->nodes (as modified above) _set->updateNodeIfInNodes(*it); } _scan->unconfirmedReplies.clear(); _scan->foundUpMaster = true; _set->lastSeenMaster = reply.host; return true; } void Refresher::receivedIsMasterBeforeFoundMaster(const IsMasterReply& reply) { invariant(!reply.isMaster); // This function doesn't alter _set at all. It only modifies the work queue in _scan. // Add everyone this host claims is in the set to possibleNodes. _scan->possibleNodes.insert(reply.normalHosts.begin(), reply.normalHosts.end()); // If this node thinks the primary is someone we haven't tried, make that the next // hostToScan. if (!reply.primary.empty() && !_scan->triedHosts.count(reply.primary)) { std::deque::iterator it = std::stable_partition( _scan->hostsToScan.begin(), _scan->hostsToScan.end(), hostIs(reply.primary)); if (it == _scan->hostsToScan.begin()) { // reply.primary wasn't in hostsToScan _scan->hostsToScan.push_front(reply.primary); } } } HostAndPort Refresher::_refreshUntilMatches(const ReadPreferenceSetting* criteria) { boost::unique_lock lk(_set->mutex); while (true) { if (criteria) { HostAndPort out = _set->getMatchingHost(*criteria); if (!out.empty()) return out; } const NextStep ns = getNextStep(); switch (ns.step) { case NextStep::DONE: DEV _set->checkInvariants(); // getNextStep may have updated nodes if no master was found. return criteria ? _set->getMatchingHost(*criteria) : HostAndPort(); case NextStep::WAIT: // TODO consider treating as DONE for refreshAll DEV _set->checkInvariants(); _set->cv.wait(lk); continue; case NextStep::CONTACT_HOST: { BSONObj reply; // empty on error int64_t pingMicros = 0; DEV _set->checkInvariants(); lk.unlock(); // relocked after attempting to call isMaster try { pingMicros = _set->connectionCache.timedIsMaster(ns.host, &reply); } catch (...) { LOG(2) << "failed to execute isMaster on host: " << ns.host; reply = BSONObj(); } lk.lock(); // Ignore the reply and return if we are no longer the current scan. This might // happen if it was decided that the host we were contacting isn't part of the set. if (_scan != _set->currentScan) return criteria ? _set->getMatchingHost(*criteria) : HostAndPort(); if (reply.isEmpty()) failedHost(ns.host); else receivedIsMaster(ns.host, pingMicros, reply); } } } } void IsMasterReply::parse(const BSONObj& obj) { try { raw = obj.getOwned(); // don't use obj again after this line ok = raw["ok"].trueValue(); if (!ok) return; setName = raw["setName"].str(); hidden = raw["hidden"].trueValue(); secondary = raw["secondary"].trueValue(); // hidden nodes can't be master, even if they claim to be. isMaster = !hidden && raw["ismaster"].trueValue(); if (isMaster && raw.hasField("electionId")) { electionId = raw["electionId"].OID(); } const string primaryString = raw["primary"].str(); primary = primaryString.empty() ? HostAndPort() : HostAndPort(primaryString); // both hosts and passives, but not arbiters, are considered "normal hosts" normalHosts.clear(); BSONForEach(host, raw.getObjectField("hosts")) { normalHosts.insert(HostAndPort(host.String())); } BSONForEach(host, raw.getObjectField("passives")) { normalHosts.insert(HostAndPort(host.String())); } tags = raw.getObjectField("tags"); } catch (const std::exception& e) { ok = false; log() << "exception while parsing isMaster reply: " << e.what() << " " << obj; } } const int64_t Node::unknownLatency = numeric_limits::max(); bool Node::matches(const ReadPreference& pref) const { if (!isUp) return false; if (pref == ReadPreference_PrimaryOnly) { return isMaster; } if (pref == ReadPreference_SecondaryOnly) { if (isMaster) return false; } return true; } bool Node::matches(const BSONObj& tag) const { BSONForEach(tagCriteria, tag) { if (this->tags[tagCriteria.fieldNameStringData()] != tagCriteria) return false; } return true; } void Node::update(const IsMasterReply& reply) { invariant(host == reply.host); invariant(reply.ok); LOG(3) << "Updating host " << host << " based on ismaster reply: " << reply.raw; // Nodes that are hidden or neither master or secondary are considered down since we can't // send any operations to them. isUp = !reply.hidden && (reply.isMaster || reply.secondary); isMaster = reply.isMaster; // save a copy if unchanged if (!tags.binaryEqual(reply.tags)) tags = reply.tags.getOwned(); if (reply.latencyMicros >= 0) { // TODO upper bound? if (latencyMicros == unknownLatency) { latencyMicros = reply.latencyMicros; } else { // update latency with smoothed moving average (1/4th the delta) latencyMicros += (reply.latencyMicros - latencyMicros) / 4; } } } ReplicaSetMonitor::ConfigChangeHook SetState::configChangeHook; uint64_t ConnectionCache::timedIsMaster(const HostAndPort& host, BSONObj* out) { bool ignoredOutParam; ConnectionGuard guard(*this, host); Timer timer; guard._conn->isMaster(ignoredOutParam, out); return timer.micros(); } boost::shared_ptr ConnectionCache::getConnectionTo(const HostAndPort& host) { { boost::lock_guard lk(_cacheLock); ConnectionMap::iterator connEntry = _cacheStorage.find(host); if (connEntry != _cacheStorage.end() && connectionOk(connEntry->second)) { boost::shared_ptr conn(connEntry->second); _cacheStorage.erase(connEntry); return conn; } } std::string errmsg; boost::shared_ptr conn(dynamic_cast( ConnectionString(host).connect(errmsg, socketTimeoutSecs))); if (!conn) { throw DBException( str::stream() << "failed to connect to " << host.toString() << ": " << errmsg, 0); } return conn; } void ConnectionCache::returnConnection(const HostAndPort& host, boost::shared_ptr conn) { boost::lock_guard lk(_cacheLock); // save our connection to the cache. We may stomp on // a connection to the same host that was created while // we were executing isMaster, but that is OK. _cacheStorage[host] = conn; } SetState::SetState(StringData name, const std::set& seedNodes) : name(name.toString()), consecutiveFailedScans(0), seedNodes(seedNodes), latencyThresholdMicros(client::Options::current().defaultLocalThresholdMillis() * 1000), rand(int64_t(time(0))), roundRobin(0) { uassert(13642, "Replica set seed list can't be empty", !seedNodes.empty()); if (name.empty()) warning() << "Replica set name empty, first node: " << *(seedNodes.begin()); // This adds the seed hosts to nodes, but they aren't usable for anything except seeding a // scan until we start a scan and either find a master or contact all hosts without finding // one. // WARNING: if seedNodes is ever changed to not imply sorted iteration, you will need to // sort nodes after this loop. for (std::set::const_iterator it = seedNodes.begin(); it != seedNodes.end(); ++it) { nodes.push_back(Node(*it)); } DEV checkInvariants(); } HostAndPort SetState::getMatchingHost(const ReadPreferenceSetting& criteria) const { switch (criteria.pref) { // "Prefered" read preferences are defined in terms of other preferences case ReadPreference_PrimaryPreferred: { HostAndPort out = getMatchingHost(ReadPreferenceSetting(ReadPreference_PrimaryOnly, criteria.tags)); // NOTE: the spec says we should use the primary even if tags don't match if (!out.empty()) return out; return getMatchingHost( ReadPreferenceSetting(ReadPreference_SecondaryOnly, criteria.tags)); } case ReadPreference_SecondaryPreferred: { HostAndPort out = getMatchingHost(ReadPreferenceSetting(ReadPreference_SecondaryOnly, criteria.tags)); if (!out.empty()) return out; // NOTE: the spec says we should use the primary even if tags don't match return getMatchingHost( ReadPreferenceSetting(ReadPreference_PrimaryOnly, criteria.tags)); } case ReadPreference_PrimaryOnly: { // NOTE: isMaster implies isUp Nodes::const_iterator it = std::find_if(nodes.begin(), nodes.end(), isMaster); if (it == nodes.end()) return HostAndPort(); return it->host; } // The difference between these is handled by Node::matches case ReadPreference_SecondaryOnly: case ReadPreference_Nearest: { BSONForEach(tagElem, criteria.tags.getTagBSON()) { uassert(16358, "Tags should be a BSON object", tagElem.isABSONObj()); BSONObj tag = tagElem.Obj(); std::vector matchingNodes; for (size_t i = 0; i < nodes.size(); i++) { if (nodes[i].matches(criteria.pref) && nodes[i].matches(tag)) { matchingNodes.push_back(&nodes[i]); } } // don't do more complicated selection if not needed if (matchingNodes.empty()) continue; if (matchingNodes.size() == 1) return matchingNodes.front()->host; // order by latency and don't consider hosts further than a threshold from the // closest. std::sort(matchingNodes.begin(), matchingNodes.end(), compareLatencies); for (size_t i = 1; i < matchingNodes.size(); i++) { int64_t distance = matchingNodes[i]->latencyMicros - matchingNodes[0]->latencyMicros; if (distance >= latencyThresholdMicros) { // this node and all remaining ones are too far away matchingNodes.erase(matchingNodes.begin() + i, matchingNodes.end()); break; } } // of the remaining nodes, pick one at random (or use round-robin) if (ReplicaSetMonitor::useDeterministicHostSelection) { // only in tests return matchingNodes[roundRobin++ % matchingNodes.size()]->host; } else { // normal case return matchingNodes[rand.nextInt32(matchingNodes.size())]->host; }; } return HostAndPort(); } default: uassert(16337, "Unknown read preference", false); break; } } Node* SetState::findNode(const HostAndPort& host) { const Nodes::iterator it = std::lower_bound(nodes.begin(), nodes.end(), host, compareHosts); if (it == nodes.end() || it->host != host) return NULL; return &(*it); } Node* SetState::findOrCreateNode(const HostAndPort& host) { // This is insertion sort, but N is currently guaranteed to be <= 12 (although this class // must function correctly even with more nodes). If we lift that restriction, we may need // to consider alternate algorithms. Nodes::iterator it = std::lower_bound(nodes.begin(), nodes.end(), host, compareHosts); if (it == nodes.end() || it->host != host) { LOG(2) << "Adding node " << host << " to our view of replica set " << name; it = nodes.insert(it, Node(host)); } return &(*it); } void SetState::updateNodeIfInNodes(const IsMasterReply& reply) { Node* node = findNode(reply.host); if (!node) { LOG(2) << "Skipping application of ismaster reply from " << reply.host << " since it isn't a confirmed member of set " << name; return; } node->update(reply); } std::string SetState::getServerAddress() const { StringBuilder ss; if (!name.empty()) ss << name << "/"; for (std::set::const_iterator it = seedNodes.begin(); it != seedNodes.end(); ++it) { if (it != seedNodes.begin()) ss << ","; it->append(ss); } return ss.str(); } void SetState::checkInvariants() const { bool foundMaster = false; for (size_t i = 0; i < nodes.size(); i++) { // no empty hosts invariant(!nodes[i].host.empty()); if (nodes[i].isMaster) { // masters must be up invariant(nodes[i].isUp); // at most one master invariant(!foundMaster); foundMaster = true; // if we have a master it should be the same as lastSeenMaster invariant(nodes[i].host == lastSeenMaster); } // should never end up with negative latencies invariant(nodes[i].latencyMicros >= 0); // nodes must be sorted by host with no-dupes invariant(i == 0 || (nodes[i - 1].host < nodes[i].host)); } // nodes should be a (non-strict) superset of the seedNodes invariant(std::includes( nodes.begin(), nodes.end(), seedNodes.begin(), seedNodes.end(), compareHosts)); if (currentScan) { // hostsToScan can't have dups or hosts already in triedHosts. std::set cantSee = currentScan->triedHosts; for (std::deque::const_iterator it = currentScan->hostsToScan.begin(); it != currentScan->hostsToScan.end(); ++it) { invariant(!cantSee.count(*it)); cantSee.insert(*it); // make sure we don't see this again } // We should only be waitingFor hosts that are in triedHosts invariant(std::includes(currentScan->triedHosts.begin(), currentScan->triedHosts.end(), currentScan->waitingFor.begin(), currentScan->waitingFor.end())); // We should only have unconfirmedReplies if we haven't found a master yet invariant(!currentScan->foundUpMaster || currentScan->unconfirmedReplies.empty()); } } template void ScanState::enqueAllUntriedHosts(const Container& container, PseudoRandom& rand) { invariant(hostsToScan.empty()); // because we don't try to dedup hosts already in the queue. // no std::copy_if before c++11 for (typename Container::const_iterator it(container.begin()), end(container.end()); it != end; ++it) { if (!triedHosts.count(*it)) { hostsToScan.push_back(*it); } } std::random_shuffle(hostsToScan.begin(), hostsToScan.end(), rand); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/replica_set_monitor.h000066400000000000000000000272251273231111400255660ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/string_data.h" #include "mongo/stdx/functional.h" #include "mongo/util/net/hostandport.h" namespace mongo { class BSONObj; class ReplicaSetMonitor; class TagSet; struct ReadPreferenceSetting; typedef boost::shared_ptr ReplicaSetMonitorPtr; /** * Holds state about a replica set and provides a means to refresh the local view. * All methods perform the required synchronization to allow callers from multiple threads. */ class ReplicaSetMonitor { MONGO_DISALLOW_COPYING(ReplicaSetMonitor); public: class Refresher; typedef stdx::function ConfigChangeHook; /** * Initializes local state. * * seeds must not be empty. */ ReplicaSetMonitor(StringData name, const std::set& seeds); /** * Returns a host matching criteria or an empty HostAndPort if no host matches. * * If no host matches initially, will then attempt to refresh our view of the set by * contacting other hosts. May still return no result if no host matches following a * refresh. */ HostAndPort getHostOrRefresh(const ReadPreferenceSetting& criteria); /** * Returns the host we think is the current master or uasserts. * * This is a thin wrapper around getHostOrRefresh so this will also refresh our view if we * don't think there is a master at first. The main difference is that this will uassert * rather than returning an empty HostAndPort. */ HostAndPort getMasterOrUassert(); /** * Returns a refresher object that can be used to update our view of the set. * If a refresh is currently in-progress, the returned Refresher will participate in the * current refresh round. */ Refresher startOrContinueRefresh(); /** * Notifies this Monitor that a host has failed and should be considered down. * * Call this when you get a connection error. If you get an error while trying to refresh * our view of a host, call Refresher::hostFailed() instead. */ void failedHost(const HostAndPort& host); /** * Returns true if this node is the master based ONLY on local data. Be careful, return may * be stale. */ bool isPrimary(const HostAndPort& host) const; /** * Returns true if host is part of this set and is considered up (meaning it can accept * queries). */ bool isHostUp(const HostAndPort& host) const; /** * How may times in a row have we tried to refresh without successfully contacting any hosts * who claim to be members of this set? */ int getConsecutiveFailedScans() const; /** * The name of the set. */ std::string getName() const; /** * Returns a string with the format name/server1,server2. * If name is empty, returns just comma-separated list of servers. */ std::string getServerAddress() const; /** * Is server part of this set? Uses only cached information. */ bool contains(const HostAndPort& server) const; /** * Writes information about our cached view of the set to a BSONObjBuilder. */ void appendInfo(BSONObjBuilder& b) const; /** * Returns true if the monitor knows a usable primary from it's interal view. */ bool isKnownToHaveGoodPrimary() const; /** * Creates a new ReplicaSetMonitor, if it doesn't already exist. */ static void createIfNeeded(const std::string& name, const std::set& servers); /** * gets a cached Monitor per name. If the monitor is not found and createFromSeed is false, * it will return none. If createFromSeed is true, it will try to look up the last known * servers list for this set and will create a new monitor using that as the seed list. */ static ReplicaSetMonitorPtr get(const std::string& name, bool createFromSeed = false); /** * Returns all the currently tracked replica set names. */ static std::set getAllTrackedSets(); /** * Removes the ReplicaSetMonitor for the given set name from _sets, which will delete it. * If clearSeedCache is true, then the cached seed string for this Replica Set will be * removed from _seedServers. */ static void remove(const std::string& name, bool clearSeedCache = false); /** * Sets the hook to be called whenever the config of any replica set changes. * Currently only 1 globally, so this asserts if one already exists. * * The hook will be called from a fresh thread. It is responsible for initializing any * thread-local state and ensuring that no exceptions escape. * * The hook must not be changed while the program has multiple threads. */ static void setConfigChangeHook(ConfigChangeHook hook); /** * Starts the ReplicaSetMonitorWatcher. You shouldn't have to call this in production code * as it is called in init.cpp. However, it may be useful to pair calls to initalize * and cleanup in tests. The behavior of other methods in this class is undefined if * initialize() has not been called. */ static Status initialize(); /** * Permanently stops all monitoring on replica sets and clears all cached information * as well. As a consequence, NEVER call this if you have other threads that have a * DBClientReplicaSet instance. After this is called, the behavior of other methods in this * class is undefined until a subsequent call to initialize. * * The gracePeriodMillis parameter determines the maximum amount of time to wait. A value * of 0 (the default) indicates no timeout. If a nonzero timeout is specified, a return value * of Status::OK() indicates that shutdown completed successfully in the allotted time. */ static Status shutdown(int gracePeriodMillis = 0); /** * If a ReplicaSetMonitor has been refreshed more than this many times in a row without * finding any live nodes claiming to be in the set, the ReplicaSetMonitorWatcher will stop * periodic background refreshes of this set. */ static int maxConsecutiveFailedChecks; // // internal types (defined in replica_set_monitor_internal.h) // struct IsMasterReply; struct ScanState; struct SetState; typedef boost::shared_ptr ScanStatePtr; typedef boost::shared_ptr SetStatePtr; // // FOR TESTING ONLY // /** * Allows tests to set initial conditions and introspect the current state. */ explicit ReplicaSetMonitor(const SetStatePtr& initialState) : _state(initialState) {} /** * Defaults to false, meaning that if multiple hosts meet a criteria we pick one at random. * This is required by the replica set driver spec. Set this to true in tests that need host * selection to be deterministic. */ static bool useDeterministicHostSelection; private: const SetStatePtr _state; // never NULL }; /** * Refreshes the local view of a replica set. * * Use ReplicaSetMonitor::startOrContinueRefresh() to obtain a Refresher. * * Multiple threads can refresh a single set without any additional synchronization, however * they must each use their own Refresher object. * * All logic related to choosing the hosts to contact and updating the SetState based on replies * lives in this class. */ class ReplicaSetMonitor::Refresher { public: /** * Contact hosts in the set to refresh our view, but stop once a host matches criteria. * Returns the matching host or empty if none match after a refresh. * * This is called by ReplicaSetMonitor::getHostWithRefresh() */ HostAndPort refreshUntilMatches(const ReadPreferenceSetting& criteria) { return _refreshUntilMatches(&criteria); }; /** * Refresh all hosts. Equivalent to refreshUntilMatches with a criteria that never * matches. * * This is intended to be called periodically, possibly from a background thread. */ void refreshAll() { _refreshUntilMatches(NULL); } // // Remaining methods are only for testing and internal use. // Callers are responsible for holding SetState::mutex before calling any of these methods. // /** * Any passed-in pointers are shared with caller. * * If no scan is in-progress, this function is responsible for setting up a new scan. */ explicit Refresher(const SetStatePtr& setState); struct NextStep { enum StepKind { CONTACT_HOST, /// Contact the returned host WAIT, /// Wait on condition variable and try again. DONE, /// No more hosts to contact in this Refresh round }; explicit NextStep(StepKind step, const HostAndPort& host = HostAndPort()) : step(step), host(host) {} StepKind step; HostAndPort host; }; /** * Returns the next step to take. * * By calling this, you promise to call receivedIsMaster or failedHost if the NextStep is * CONTACT_HOST. */ NextStep getNextStep(); /** * Call this if a host returned from getNextStep successfully replied to an isMaster call. * Negative latencyMicros are ignored. */ void receivedIsMaster(const HostAndPort& from, int64_t latencyMicros, const BSONObj& reply); /** * Call this if a host returned from getNextStep failed to reply to an isMaster call. */ void failedHost(const HostAndPort& host); /** * True if this Refresher started a new full scan rather than joining an existing one. */ bool startedNewScan() const { return _startedNewScan; } /** * Starts a new scan over the hosts in set. */ static ScanStatePtr startNewScan(const SetState* set); private: /** * First, checks that the "reply" is not from a stale primary by * comparing the electionId of "reply" to the maxElectionId recorded by the SetState. * Returns true if "reply" belongs to a non-stale primary. * * Updates _set and _scan based on set-membership information from a master. * Applies _scan->unconfirmedReplies to confirmed nodes. * Does not update this host's node in _set->nodes. */ bool receivedIsMasterFromMaster(const IsMasterReply& reply); /** * Adjusts the _scan work queue based on information from this host. * This should only be called with replies from non-masters. * Does not update _set at all. */ void receivedIsMasterBeforeFoundMaster(const IsMasterReply& reply); /** * Shared implementation of refreshUntilMatches and refreshAll. * NULL criteria means refresh every host. * Handles own locking. */ HostAndPort _refreshUntilMatches(const ReadPreferenceSetting* criteria); // Both pointers are never NULL SetStatePtr _set; ScanStatePtr _scan; // May differ from _set->currentScan if a new scan has started. bool _startedNewScan; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/replica_set_monitor_internal.h000066400000000000000000000216061273231111400274570ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This is an internal header. * This should only be included by replica_set_monitor.cpp and replica_set_monitor_test.cpp. * This should never be included by any header. */ #pragma once #include #include #include #include #include #include "mongo/base/disallow_copying.h" #include "mongo/client/dbclient_rs.h" // for TagSet and ReadPreferenceSettings #include "mongo/client/replica_set_monitor.h" #include "mongo/db/jsobj.h" #include "mongo/platform/cstdint.h" #include "mongo/platform/random.h" #include "mongo/platform/unordered_map.h" #include "mongo/util/net/hostandport.h" namespace mongo { // Internal connection cache for isMaster. Used to amortize the cost of establishing connections // to a remote host. Not really a pool because we only keep one connection per host. class ConnectionCache { public: // Uses a cached connection (may need to reconnect) to execute a remote isMaster call // on the given host. Returns microseconds taken for remote call to complete. Throws. uint64_t timedIsMaster(const HostAndPort& host, BSONObj* out); private: typedef unordered_map > ConnectionMap; // Guard that creates a connection if needed, or removes it from // the cache. This is so multiple isMaster calls can be in flight in the same // set simultaneously. class ConnectionGuard { public: // Lifetime of guard must be subset of lifetime of host ConnectionGuard(ConnectionCache& cache, const HostAndPort& host) : _cache(cache), _host(host) { // this could throw. _conn = _cache.getConnectionTo(_host); } ~ConnectionGuard() { _cache.returnConnection(_host, _conn); } boost::shared_ptr _conn; // Reference to owner. ConnectionCache& _cache; const HostAndPort& _host; }; // If we don't have a connection to this host cached, // or we have one that is dead, we reconnect and return // If we have one, we remove it from the cache and return it boost::shared_ptr getConnectionTo(const HostAndPort& host); void returnConnection(const HostAndPort& host, boost::shared_ptr conn); inline bool connectionOk(const boost::shared_ptr& conn) { // checks are ordered from cheap to expensive return conn && !conn->isFailed() && conn->isStillConnected(); } ConnectionMap _cacheStorage; boost::mutex _cacheLock; }; struct ReplicaSetMonitor::IsMasterReply { IsMasterReply() : ok(false) {} IsMasterReply(const HostAndPort& host, int64_t latencyMicros, const BSONObj& reply) : ok(false), host(host), latencyMicros(latencyMicros) { parse(reply); } /** * Never throws. If parsing fails for any reason, sets ok to false. */ void parse(const BSONObj& obj); bool ok; // if false, ignore all other fields BSONObj raw; // Always owned. Other fields are allowed to be a view into this. std::string setName; bool isMaster; bool secondary; bool hidden; OID electionId; // Set if this isMaster reply is from the primary HostAndPort primary; // empty if not present std::set normalHosts; // both "hosts" and "passives" BSONObj tags; // remaining fields aren't in isMaster reply, but are known to caller. HostAndPort host; int64_t latencyMicros; // ignored if negative }; struct ReplicaSetMonitor::SetState { MONGO_DISALLOW_COPYING(SetState); public: // A single node in the replicaSet struct Node { explicit Node(const HostAndPort& host) : host(host), latencyMicros(unknownLatency) { markFailed(); } void markFailed() { isUp = false; isMaster = false; } bool matches(const ReadPreference& pref) const; /** * Checks if the given tag matches the tag attached to this node. * * Example: * * Tag of this node: { "dc": "nyc", "region": "na", "rack": "4" } * * match: {} * match: { "dc": "nyc", "rack": 4 } * match: { "region": "na", "dc": "nyc" } * not match: { "dc": "nyc", "rack": 2 } * not match: { "dc": "sf" } */ bool matches(const BSONObj& tag) const; /** * Updates this Node based on information in reply. The reply must be from this host. */ void update(const IsMasterReply& reply); // Intentionally chosen to compare worse than all known latencies. static const int64_t unknownLatency; // = numeric_limits::max() HostAndPort host; bool isUp; bool isMaster; // implies isUp int64_t latencyMicros; // unknownLatency if unknown BSONObj tags; // owned }; typedef std::vector Nodes; /** * seedNodes must not be empty */ SetState(StringData name, const std::set& seedNodes); /** * Returns a host matching criteria or an empty host if no known host matches. * * Note: Uses only local data and does not go over the network. */ HostAndPort getMatchingHost(const ReadPreferenceSetting& criteria) const; /** * Returns the Node with the given host, or NULL if no Node has that host. */ Node* findNode(const HostAndPort& host); /** * Returns the Node with the given host, or creates one if no Node has that host. * Maintains the sorted order of nodes. */ Node* findOrCreateNode(const HostAndPort& host); void updateNodeIfInNodes(const IsMasterReply& reply); std::string getServerAddress() const; /** * Before unlocking, do DEV checkInvariants(); */ void checkInvariants() const; static ConfigChangeHook configChangeHook; boost::mutex mutex; // must hold this to access any other member or method (except name). // If Refresher::getNextStep returns WAIT, you should wait on the condition_variable, // releasing mutex. It will be notified when either getNextStep will return something other // than WAIT, or a new host is available for consideration by getMatchingHost. Essentially, // this will be hit whenever the _refreshUntilMatches loop has the potential to make // progress. // TODO consider splitting cv into two: one for when looking for a master, one for all other // cases. boost::condition_variable cv; const std::string name; // safe to read outside lock since it is const int consecutiveFailedScans; std::set seedNodes; // updated whenever a master reports set membership changes OID maxElectionId; // largest election id observed by this ReplicaSetMonitor HostAndPort lastSeenMaster; // empty if we have never seen a master. can be same as current Nodes nodes; // maintained sorted and unique by host ScanStatePtr currentScan; // NULL if no scan in progress int64_t latencyThresholdMicros; mutable PseudoRandom rand; // only used for host selection to balance load mutable int roundRobin; // used when useDeterministicHostSelection is true mutable ConnectionCache connectionCache; }; struct ReplicaSetMonitor::ScanState { MONGO_DISALLOW_COPYING(ScanState); public: ScanState() : foundUpMaster(false), foundAnyUpNodes(false) {} /** * Adds all hosts in container that aren't in triedHosts to hostsToScan, then shuffles the * queue. */ template void enqueAllUntriedHosts(const Container& container, PseudoRandom& rand); // Access to fields is guarded by associated SetState's mutex. bool foundUpMaster; bool foundAnyUpNodes; std::deque hostsToScan; // Work queue. std::set possibleNodes; // Nodes reported by non-primary hosts. std::set waitingFor; // Hosts we have dispatched but haven't replied yet. std::set triedHosts; // Hosts that have been returned from getNextStep. // All responses go here until we find a master. typedef std::vector UnconfirmedReplies; UnconfirmedReplies unconfirmedReplies; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/replica_set_monitor_test.cpp000066400000000000000000001160061273231111400271540ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/replica_set_monitor.h" #include #include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclient_rs.h" #include "mongo/client/replica_set_monitor_internal.h" #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" using namespace std; using namespace mongo; // Pull nested types to top-level scope typedef ReplicaSetMonitor::IsMasterReply IsMasterReply; typedef ReplicaSetMonitor::ScanState ScanState; typedef ReplicaSetMonitor::ScanStatePtr ScanStatePtr; typedef ReplicaSetMonitor::SetState SetState; typedef ReplicaSetMonitor::SetStatePtr SetStatePtr; typedef ReplicaSetMonitor::Refresher Refresher; typedef Refresher::NextStep NextStep; typedef ScanState::UnconfirmedReplies UnconfirmedReplies; typedef SetState::Node Node; typedef SetState::Nodes Nodes; std::vector basicSeedsBuilder() { std::vector out; out.push_back(HostAndPort("a")); out.push_back(HostAndPort("b")); out.push_back(HostAndPort("c")); return out; } const std::vector basicSeeds = basicSeedsBuilder(); const std::set basicSeedsSet(basicSeeds.begin(), basicSeeds.end()); // NOTE: Unless stated otherwise, all tests assume exclusive access to state belongs to the // current (only) thread, so they do not lock SetState::mutex before examining state. This is // NOT something that non-test code should do. TEST(ReplicaSetMonitorTests, InitialState) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); ASSERT_EQUALS(state->name, "name"); ASSERT(state->seedNodes == basicSeedsSet); ASSERT(state->lastSeenMaster.empty()); ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(!node->isUp); ASSERT(!node->isMaster); ASSERT(node->tags.isEmpty()); } } TEST(ReplicaSetMonitorTests, IsMasterBadParse) { BSONObj ismaster = BSON("hosts" << BSON_ARRAY("mongo.example:badport")); IsMasterReply imr(HostAndPort("mongo.example:27017"), -1, ismaster); ASSERT_EQUALS(imr.ok, false); } TEST(ReplicaSetMonitorTests, IsMasterReplyRSNotInitiated) { BSONObj ismaster = BSON( "ismaster" << false << "secondary" << false << "info" << "can't get local.system.replset config from self or any seed (EMPTYCONFIG)" << "isreplicaset" << true << "maxBsonObjectSize" << 16777216 << "maxMessageSizeBytes" << 48000000 << "maxWriteBatchSize" << 1000 << "localTime" << mongo::jsTime() << "maxWireVersion" << 2 << "minWireVersion" << 0 << "ok" << 1); IsMasterReply imr(HostAndPort(), -1, ismaster); ASSERT_EQUALS(imr.ok, true); ASSERT_EQUALS(imr.setName, ""); ASSERT_EQUALS(imr.hidden, false); ASSERT_EQUALS(imr.secondary, false); ASSERT_EQUALS(imr.isMaster, false); ASSERT(imr.primary.empty()); ASSERT(imr.normalHosts.empty()); ASSERT(imr.tags.isEmpty()); } TEST(ReplicaSetMonitorTests, IsMasterReplyRSPrimary) { BSONObj ismaster = BSON("setName" << "test" << "setVersion" << 1 << "ismaster" << true << "secondary" << false << "hosts" << BSON_ARRAY("mongo.example:3000") << "primary" << "mongo.example:3000" << "me" << "mongo.example:3000" << "maxBsonObjectSize" << 16777216 << "maxMessageSizeBytes" << 48000000 << "maxWriteBatchSize" << 1000 << "localTime" << mongo::jsTime() << "maxWireVersion" << 2 << "minWireVersion" << 0 << "ok" << 1); IsMasterReply imr(HostAndPort("mongo.example:3000"), -1, ismaster); ASSERT_EQUALS(imr.ok, true); ASSERT_EQUALS(imr.host.toString(), HostAndPort("mongo.example:3000").toString()); ASSERT_EQUALS(imr.setName, "test"); ASSERT_EQUALS(imr.hidden, false); ASSERT_EQUALS(imr.secondary, false); ASSERT_EQUALS(imr.isMaster, true); ASSERT_EQUALS(imr.primary.toString(), HostAndPort("mongo.example:3000").toString()); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3000"))); ASSERT(imr.tags.isEmpty()); } TEST(ReplicaSetMonitorTests, IsMasterReplyPassiveSecondary) { BSONObj ismaster = BSON("setName" << "test" << "setVersion" << 1 << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("mongo.example:3000") << "passives" << BSON_ARRAY("mongo.example:3001") << "primary" << "mongo.example:3000" << "passive" << true << "me" << "mongo.example:3001" << "maxBsonObjectSize" << 16777216 << "maxMessageSizeBytes" << 48000000 << "maxWriteBatchSize" << 1000 << "localTime" << mongo::jsTime() << "maxWireVersion" << 2 << "minWireVersion" << 0 << "ok" << 1); IsMasterReply imr(HostAndPort("mongo.example:3001"), -1, ismaster); ASSERT_EQUALS(imr.ok, true); ASSERT_EQUALS(imr.host.toString(), HostAndPort("mongo.example:3001").toString()); ASSERT_EQUALS(imr.setName, "test"); ASSERT_EQUALS(imr.hidden, false); ASSERT_EQUALS(imr.secondary, true); ASSERT_EQUALS(imr.isMaster, false); ASSERT_EQUALS(imr.primary.toString(), HostAndPort("mongo.example:3000").toString()); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3000"))); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3001"))); ASSERT(imr.tags.isEmpty()); } TEST(ReplicaSetMonitorTests, IsMasterReplyHiddenSecondary) { BSONObj ismaster = BSON("setName" << "test" << "setVersion" << 1 << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("mongo.example:3000") << "primary" << "mongo.example:3000" << "passive" << true << "hidden" << true << "me" << "mongo.example:3001" << "maxBsonObjectSize" << 16777216 << "maxMessageSizeBytes" << 48000000 << "maxWriteBatchSize" << 1000 << "localTime" << mongo::jsTime() << "maxWireVersion" << 2 << "minWireVersion" << 0 << "ok" << 1); IsMasterReply imr(HostAndPort("mongo.example:3001"), -1, ismaster); ASSERT_EQUALS(imr.ok, true); ASSERT_EQUALS(imr.host.toString(), HostAndPort("mongo.example:3001").toString()); ASSERT_EQUALS(imr.setName, "test"); ASSERT_EQUALS(imr.hidden, true); ASSERT_EQUALS(imr.secondary, true); ASSERT_EQUALS(imr.isMaster, false); ASSERT_EQUALS(imr.primary.toString(), HostAndPort("mongo.example:3000").toString()); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3000"))); ASSERT(imr.tags.isEmpty()); } TEST(ReplicaSetMonitorTests, IsMasterSecondaryWithTags) { BSONObj ismaster = BSON("setName" << "test" << "setVersion" << 1 << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("mongo.example:3000" << "mongo.example:3001") << "primary" << "mongo.example:3000" << "me" << "mongo.example:3001" << "maxBsonObjectSize" << 16777216 << "maxMessageSizeBytes" << 48000000 << "maxWriteBatchSize" << 1000 << "localTime" << mongo::jsTime() << "maxWireVersion" << 2 << "minWireVersion" << 0 << "tags" << BSON("dc" << "nyc" << "use" << "production") << "ok" << 1); IsMasterReply imr(HostAndPort("mongo.example:3001"), -1, ismaster); ASSERT_EQUALS(imr.ok, true); ASSERT_EQUALS(imr.host.toString(), HostAndPort("mongo.example:3001").toString()); ASSERT_EQUALS(imr.setName, "test"); ASSERT_EQUALS(imr.hidden, false); ASSERT_EQUALS(imr.secondary, true); ASSERT_EQUALS(imr.isMaster, false); ASSERT_EQUALS(imr.primary.toString(), HostAndPort("mongo.example:3000").toString()); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3000"))); ASSERT(imr.normalHosts.count(HostAndPort("mongo.example:3001"))); ASSERT(imr.tags.hasElement("dc")); ASSERT(imr.tags.hasElement("use")); ASSERT_EQUALS(imr.tags["dc"].str(), "nyc"); ASSERT_EQUALS(imr.tags["use"].str(), "production"); } TEST(ReplicaSetMonitorTests, CheckAllSeedsSerial) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; for (size_t i = 0; i < basicSeeds.size(); i++) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); // mock a reply bool primary = ns.host.host() == "a"; refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); } NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // validate final state ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, node->host.host() == "a"); ASSERT(node->tags.isEmpty()); } } TEST(ReplicaSetMonitorTests, CheckAllSeedsParallel) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; // get all hosts to contact first for (size_t i = 0; i < basicSeeds.size(); i++) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); } // mock all replies for (size_t i = 0; i < basicSeeds.size(); i++) { // All hosts to talk to are already dispatched, but no reply has been received NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::WAIT); ASSERT(ns.host.empty()); bool primary = i == 0; refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); } // Now all hosts have returned data NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // validate final state ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, i == 0); ASSERT(node->tags.isEmpty()); } } TEST(ReplicaSetMonitorTests, NoMasterInitAllUp) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; for (size_t i = 0; i < basicSeeds.size(); i++) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); // mock a reply refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); } NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // validate final state ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, false); ASSERT(node->tags.isEmpty()); } } TEST(ReplicaSetMonitorTests, MasterNotInSeeds_NoPrimaryInIsMaster) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; for (size_t i = 0; i < basicSeeds.size(); i++) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); // mock a reply refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("a" << "b" << "c" << "d") << "ok" << true)); } // Only look at "d" after exhausting all other hosts NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT_EQUALS(ns.host.host(), "d"); refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "hosts" << BSON_ARRAY("a" << "b" << "c" << "d") << "ok" << true)); ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // validate final state ASSERT_EQUALS(state->nodes.size(), basicSeeds.size() + 1); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, false); ASSERT(node->tags.isEmpty()); } Node* node = state->findNode(HostAndPort("d")); ASSERT(node); ASSERT_EQUALS(node->host.host(), "d"); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, true); ASSERT(node->tags.isEmpty()); } TEST(ReplicaSetMonitorTests, MasterNotInSeeds_PrimaryInIsMaster) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; for (size_t i = 0; i < basicSeeds.size() + 1; i++) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); if (i == 1) { // d should be the second host we contact since we are told it is primary ASSERT_EQUALS(ns.host.host(), "d"); } else { ASSERT(basicSeedsSet.count(ns.host)); } ASSERT(!seen.count(ns.host)); seen.insert(ns.host); // mock a reply bool primary = ns.host.host() == "d"; refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "primary" << "d" << "hosts" << BSON_ARRAY("a" << "b" << "c" << "d") << "ok" << true)); } NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // validate final state ASSERT_EQUALS(state->nodes.size(), basicSeeds.size() + 1); for (size_t i = 0; i < basicSeeds.size(); i++) { Node* node = state->findNode(basicSeeds[i]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[i].toString()); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, false); ASSERT(node->tags.isEmpty()); } Node* node = state->findNode(HostAndPort("d")); ASSERT(node); ASSERT_EQUALS(node->host.host(), "d"); ASSERT(node->isUp); ASSERT_EQUALS(node->isMaster, true); ASSERT(node->tags.isEmpty()); } // Make sure we can use slaves we find even if we can't find a primary TEST(ReplicaSetMonitorTests, SlavesUsableEvenIfNoMaster) { std::set seeds; seeds.insert(HostAndPort("a")); SetStatePtr state = boost::make_shared("name", seeds); Refresher refresher(state); const ReadPreferenceSetting secondary(ReadPreference_SecondaryOnly, TagSet()); // Mock a reply from the only host we know about and have it claim to not be master or know // about any other hosts. This leaves the scan with no more hosts to scan, but all hosts are // still marked as down since we never contacted a master. The next call to // Refresher::getNextStep will apply all unconfimedReplies and return DONE. NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT_EQUALS(ns.host.host(), "a"); refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("a") << "ok" << true)); // Check intended conditions for entry to refreshUntilMatches. ASSERT(state->currentScan->hostsToScan.empty()); ASSERT(state->currentScan->waitingFor.empty()); ASSERT(state->currentScan->possibleNodes == state->currentScan->triedHosts); ASSERT(state->getMatchingHost(secondary).empty()); // This calls getNextStep after not finding a matching host. We want to ensure that it checks // again after being told that there are no more hosts to contact. ASSERT(!refresher.refreshUntilMatches(secondary).empty()); // Future calls should be able to return directly from the cached data. ASSERT(!state->getMatchingHost(secondary).empty()); } // Test multiple nodes that claim to be master (we use a last-wins policy) TEST(ReplicaSetMonitorTests, MultipleMasterLastNodeWins) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; // get all hosts to contact first for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); } const ReadPreferenceSetting primaryOnly(ReadPreference_PrimaryOnly, TagSet()); // mock all replies for (size_t i = 0; i != basicSeeds.size(); ++i) { // All hosts to talk to are already dispatched, but no reply has been received NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::WAIT); ASSERT(ns.host.empty()); refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); // Ensure the set primary is the host we just got a reply from HostAndPort currentPrimary = state->getMatchingHost(primaryOnly); ASSERT_EQUALS(currentPrimary.host(), basicSeeds[i].host()); ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); // Check the state of each individual node for (size_t j = 0; j != basicSeeds.size(); ++j) { Node* node = state->findNode(basicSeeds[j]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[j].toString()); ASSERT_EQUALS(node->isUp, j <= i); ASSERT_EQUALS(node->isMaster, j == i); ASSERT(node->tags.isEmpty()); } } // Now all hosts have returned data NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); } // Test nodes disagree about who is in the set, master is source of truth TEST(ReplicaSetMonitorTests, MasterIsSourceOfTruth) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); BSONArray primaryHosts = BSON_ARRAY("a" << "b" << "d"); BSONArray secondaryHosts = BSON_ARRAY("a" << "b" << "c"); // mock all replies NextStep ns = refresher.getNextStep(); while (ns.step == NextStep::CONTACT_HOST) { bool primary = ns.host.host() == "a"; refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "hosts" << (primary ? primaryHosts : secondaryHosts) << "ok" << true)); ns = refresher.getNextStep(); } // Ensure that we have heard from all hosts and scan is done ASSERT_EQUALS(ns.step, NextStep::DONE); // Ensure that d is in the set but c is not ASSERT(state->findNode(HostAndPort("d"))); ASSERT(!state->findNode(HostAndPort("c"))); } // Test multiple master nodes that disagree about set membership TEST(ReplicaSetMonitorTests, MultipleMastersDisagree) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); BSONArray hostsForSeed[3]; hostsForSeed[0] = BSON_ARRAY("a" << "b" << "c" << "d"); hostsForSeed[1] = BSON_ARRAY("a" << "b" << "c" << "e"); hostsForSeed[2] = hostsForSeed[0]; set seen; for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); } const ReadPreferenceSetting primaryOnly(ReadPreference_PrimaryOnly, TagSet()); // mock all replies for (size_t i = 0; i != basicSeeds.size(); ++i) { refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "hosts" << hostsForSeed[i % 2] << "ok" << true)); // Ensure the primary is the host we just got a reply from HostAndPort currentPrimary = state->getMatchingHost(primaryOnly); ASSERT_EQUALS(currentPrimary.host(), basicSeeds[i].host()); // Ensure each primary discovered becomes source of truth if (i == 1) { // "b" thinks node "e" is a member but "d" is not ASSERT(state->findNode(HostAndPort("e"))); ASSERT(!state->findNode(HostAndPort("d"))); } else { // "a" and "c" think node "d" is a member but "e" is not ASSERT(state->findNode(HostAndPort("d"))); ASSERT(!state->findNode(HostAndPort("e"))); } } // next step should be to contact "d" NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT_EQUALS(ns.host.host(), "d"); seen.insert(ns.host); // reply from "d" refresher.receivedIsMaster(HostAndPort("d"), -1, BSON("setName" << "name" << "ismaster" << false << "secondary" << true << "hosts" << hostsForSeed[0] << "ok" << true)); // scan should be complete ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); // Validate final state (only "c" should be master and "d" was added) ASSERT_EQUALS(state->nodes.size(), basicSeeds.size() + 1); std::vector nodes = state->nodes; for (std::vector::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { const Node& node = *it; ASSERT(node.isUp); ASSERT_EQUALS(node.isMaster, node.host.host() == "c"); ASSERT(seen.count(node.host)); } } // Ensure getMatchingHost returns hosts even if scan is ongoing TEST(ReplicaSetMonitorTests, GetMatchingDuringScan) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); const ReadPreferenceSetting primaryOnly(ReadPreference_PrimaryOnly, TagSet()); const ReadPreferenceSetting secondaryOnly(ReadPreference_SecondaryOnly, TagSet()); for (std::vector::const_iterator it = basicSeeds.begin(); it != basicSeeds.end(); ++it) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(state->getMatchingHost(primaryOnly).empty()); ASSERT(state->getMatchingHost(secondaryOnly).empty()); } // mock replies and validate set state as replies come back for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::WAIT); ASSERT(ns.host.empty()); bool primary = (i == 1); refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); bool hasPrimary = !(state->getMatchingHost(primaryOnly).empty()); bool hasSecondary = !(state->getMatchingHost(secondaryOnly).empty()); // secondary node has not been confirmed by primary until i == 1 if (i >= 1) { ASSERT(hasPrimary); ASSERT(hasSecondary); } else { ASSERT(!hasPrimary); ASSERT(!hasSecondary); } } NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); } // Ensure nothing breaks when out-of-band failedHost is called during scan TEST(ReplicaSetMonitorTests, OutOfBandFailedHost) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); ReplicaSetMonitorPtr rsm = boost::make_shared(state); Refresher refresher = rsm->startOrContinueRefresh(); for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); } for (size_t i = 0; i != basicSeeds.size(); ++i) { bool primary = (i == 0); refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); if (i >= 1) { HostAndPort a("a"); rsm->failedHost(a); Node* node = state->findNode(a); ASSERT(node); ASSERT(!node->isUp); ASSERT(!node->isMaster); } else { Node* node = state->findNode(HostAndPort("a")); ASSERT(node); ASSERT(node->isUp); ASSERT(node->isMaster); } } } // Newly elected primary with electionId >= maximum electionId seen by the Refresher TEST(ReplicaSetMonitorTests, NewPrimaryWithMaxElectionId) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; // get all hosts to contact first for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); } const ReadPreferenceSetting primaryOnly(ReadPreference_PrimaryOnly, TagSet()); // mock all replies for (size_t i = 0; i != basicSeeds.size(); ++i) { // All hosts to talk to are already dispatched, but no reply has been received NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::WAIT); ASSERT(ns.host.empty()); refresher.receivedIsMaster(basicSeeds[i], -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "hosts" << BSON_ARRAY("a" << "b" << "c") << "electionId" << OID::gen() << "ok" << true)); // Ensure the set primary is the host we just got a reply from HostAndPort currentPrimary = state->getMatchingHost(primaryOnly); ASSERT_EQUALS(currentPrimary.host(), basicSeeds[i].host()); ASSERT_EQUALS(state->nodes.size(), basicSeeds.size()); // Check the state of each individual node for (size_t j = 0; j != basicSeeds.size(); ++j) { Node* node = state->findNode(basicSeeds[j]); ASSERT(node); ASSERT_EQUALS(node->host.toString(), basicSeeds[j].toString()); ASSERT_EQUALS(node->isUp, j <= i); ASSERT_EQUALS(node->isMaster, j == i); ASSERT(node->tags.isEmpty()); } } // Now all hosts have returned data NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); } // Ignore electionId of secondaries TEST(ReplicaSetMonitorTests, IgnoreElectionIdFromSecondaries) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); set seen; const OID primaryElectionId = OID::gen(); // mock all replies for (size_t i = 0; i != basicSeeds.size(); ++i) { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); // mock a reply const bool primary = ns.host.host() == "a"; refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << primary << "secondary" << !primary << "electionId" << (primary ? primaryElectionId : OID::gen()) << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); } // check that the SetState's maxElectionId == primary's electionId ASSERT_EQUALS(state->maxElectionId, primaryElectionId); // Now all hosts have returned data NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); } // Stale Primary with obsolete electionId TEST(ReplicaSetMonitorTests, StalePrimaryWithObsoleteElectionId) { SetStatePtr state = boost::make_shared("name", basicSeedsSet); Refresher refresher(state); const OID firstElectionId = OID::gen(); const OID secondElectionId = OID::gen(); set seen; // contact first host claiming to be primary with greater electionId { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "electionId" << secondElectionId << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); Node* node = state->findNode(ns.host); ASSERT(node); ASSERT_TRUE(node->isMaster); ASSERT_EQUALS(state->maxElectionId, secondElectionId); } // contact second host claiming to be primary with smaller electionId { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << true << "secondary" << false << "electionId" << firstElectionId << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); Node* node = state->findNode(ns.host); ASSERT(node); // The SetState shouldn't see this host as master ASSERT_FALSE(node->isMaster); // the max electionId should remain the same ASSERT_EQUALS(state->maxElectionId, secondElectionId); } // third host is a secondary { NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::CONTACT_HOST); ASSERT(basicSeedsSet.count(ns.host)); ASSERT(!seen.count(ns.host)); seen.insert(ns.host); refresher.receivedIsMaster(ns.host, -1, BSON("setName" << "name" << "ismaster" << false << "secondary" << true << "hosts" << BSON_ARRAY("a" << "b" << "c") << "ok" << true)); Node* node = state->findNode(ns.host); ASSERT(node); ASSERT_FALSE(node->isMaster); // the max electionId should remain the same ASSERT_EQUALS(state->maxElectionId, secondElectionId); } // Now all hosts have returned data NextStep ns = refresher.getNextStep(); ASSERT_EQUALS(ns.step, NextStep::DONE); ASSERT(ns.host.empty()); } TEST(ReplicaSetMonitor, NoPrimaryUpCheck) { SetStatePtr state(new SetState("name", basicSeedsSet)); ReplicaSetMonitor rsm(state); ASSERT_FALSE(rsm.isKnownToHaveGoodPrimary()); } TEST(ReplicaSetMonitor, PrimaryIsUpCheck) { SetStatePtr state(new SetState("name", basicSeedsSet)); state->nodes.front().isMaster = true; ReplicaSetMonitor rsm(state); ASSERT_TRUE(rsm.isKnownToHaveGoodPrimary()); } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_authenticate.cpp000066400000000000000000000063461273231111400271170ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/sasl_client_authenticate.h" #include #include "mongo/base/string_data.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/util/base64.h" #include "mongo/util/mongoutils/str.h" namespace mongo { using namespace mongoutils; Status (*saslClientAuthenticate)(DBClientWithCommands* client, const BSONObj& saslParameters) = NULL; const char* const saslStartCommandName = "saslStart"; const char* const saslContinueCommandName = "saslContinue"; const char* const saslCommandAutoAuthorizeFieldName = "autoAuthorize"; const char* const saslCommandCodeFieldName = "code"; const char* const saslCommandConversationIdFieldName = "conversationId"; const char* const saslCommandDoneFieldName = "done"; const char* const saslCommandErrmsgFieldName = "errmsg"; const char* const saslCommandMechanismFieldName = "mechanism"; const char* const saslCommandMechanismListFieldName = "supportedMechanisms"; const char* const saslCommandPasswordFieldName = "pwd"; const char* const saslCommandPayloadFieldName = "payload"; const char* const saslCommandUserDBFieldName = "db"; const char* const saslCommandUserFieldName = "user"; const char* const saslCommandServiceHostnameFieldName = "serviceHostname"; const char* const saslCommandServiceNameFieldName = "serviceName"; const char* const saslCommandDigestPasswordFieldName = "digestPassword"; const char* const saslDefaultDBName = "$external"; const char* const saslDefaultServiceName = "mongodb"; Status saslExtractPayload(const BSONObj& cmdObj, std::string* payload, BSONType* type) { BSONElement payloadElement; Status status = bsonExtractField(cmdObj, saslCommandPayloadFieldName, &payloadElement); if (!status.isOK()) return status; *type = payloadElement.type(); if (payloadElement.type() == BinData) { const char* payloadData; int payloadLen; payloadData = payloadElement.binData(payloadLen); if (payloadLen < 0) return Status(ErrorCodes::InvalidLength, "Negative payload length"); *payload = std::string(payloadData, payloadData + payloadLen); } else if (payloadElement.type() == String) { try { *payload = base64::decode(payloadElement.str()); } catch (UserException& e) { return Status(ErrorCodes::FailedToParse, e.what()); } } else { return Status(ErrorCodes::TypeMismatch, (str::stream() << "Wrong type for field; expected BinData or String for " << payloadElement)); } return Status::OK(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_authenticate.h000066400000000000000000000141441273231111400265570ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" #include "mongo/bson/bsontypes.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/export_macros.h" namespace mongo { class BSONObj; /** * Attempts to authenticate "client" using the SASL protocol. * * Do not use directly in client code. Use the DBClientWithCommands::auth(const BSONObj&) * method, instead. * * Test against NULL for availability. Client driver must be compiled with SASL support _and_ * client application must have successfully executed mongo::runGlobalInitializersOrDie() or its * ilk to make this functionality available. * * The "saslParameters" BSONObj should be initialized with zero or more of the * fields below. Which fields are required depends on the mechanism. Consult the * relevant IETF standards. * * "mechanism": The string name of the sasl mechanism to use. Mandatory. * "autoAuthorize": Truthy values tell the server to automatically acquire privileges on * all resources after successful authentication, which is the default. Falsey values * instruct the server to await separate privilege-acquisition commands. * "user": The string name of the user to authenticate. * "db": The database target of the auth command, which identifies the location * of the credential information for the user. May be "$external" if credential * information is stored outside of the mongo cluster. * "pwd": The password. * "serviceName": The GSSAPI service name to use. Defaults to "mongodb". * "serviceHostname": The GSSAPI hostname to use. Defaults to the name of the remote host. * * Other fields in saslParameters are silently ignored. * * Returns an OK status on success, and ErrorCodes::AuthenticationFailed if authentication is * rejected. Other failures, all of which are tantamount to authentication failure, may also be * returned. */ extern MONGO_CLIENT_API Status(MONGO_CLIENT_FUNC* saslClientAuthenticate)( DBClientWithCommands* client, const BSONObj& saslParameters); /** * Extracts the payload field from "cmdObj", and store it into "*payload". * * Sets "*type" to the BSONType of the payload field in cmdObj. * * If the type of the payload field is String, the contents base64 decodes and * stores into "*payload". If the type is BinData, the contents are stored directly * into "*payload". In all other cases, returns */ MONGO_CLIENT_API Status MONGO_CLIENT_FUNC saslExtractPayload(const BSONObj& cmdObj, std::string* payload, BSONType* type); // Constants /// String name of the saslStart command. extern MONGO_CLIENT_API const char* const saslStartCommandName; /// String name of the saslContinue command. extern MONGO_CLIENT_API const char* const saslContinueCommandName; /// Name of the saslStart parameter indicating that the server should automatically grant the /// connection all privileges associated with the user after successful authentication. extern MONGO_CLIENT_API const char* const saslCommandAutoAuthorizeFieldName; /// Name of the field contain the status code in responses from the server. extern MONGO_CLIENT_API const char* const saslCommandCodeFieldName; /// Name of the field containing the conversation identifier in server respones and saslContinue /// commands. extern MONGO_CLIENT_API const char* const saslCommandConversationIdFieldName; /// Name of the field that indicates whether or not the server believes authentication has /// completed successfully. extern MONGO_CLIENT_API const char* const saslCommandDoneFieldName; /// Field in which to store error messages associated with non-success return codes. extern MONGO_CLIENT_API const char* const saslCommandErrmsgFieldName; /// Name of parameter to saslStart command indiciating the client's desired sasl mechanism. extern MONGO_CLIENT_API const char* const saslCommandMechanismFieldName; /// In the event that saslStart supplies an unsupported mechanism, the server responds with a /// field by this name, with a list of supported mechanisms. extern MONGO_CLIENT_API const char* const saslCommandMechanismListFieldName; /// Field containing password information for saslClientAuthenticate(). extern MONGO_CLIENT_API const char* const saslCommandPasswordFieldName; /// Field containing sasl payloads passed to and from the server. extern MONGO_CLIENT_API const char* const saslCommandPayloadFieldName; /// Field containing the string identifier of the user to authenticate in /// saslClientAuthenticate(). extern MONGO_CLIENT_API const char* const saslCommandUserFieldName; /// Field containing the string identifier of the database containing credential information, /// or "$external" if the credential information is stored outside of the mongo cluster. extern MONGO_CLIENT_API const char* const saslCommandUserDBFieldName; /// Field overriding the FQDN of the hostname hosting the mongodb srevice in /// saslClientAuthenticate(). extern MONGO_CLIENT_API const char* const saslCommandServiceHostnameFieldName; /// Field overriding the name of the mongodb service saslClientAuthenticate(). extern MONGO_CLIENT_API const char* const saslCommandServiceNameFieldName; /// Default database against which sasl authentication commands should run. extern MONGO_CLIENT_API const char* const saslDefaultDBName; /// Default sasl service name, "mongodb". extern MONGO_CLIENT_API const char* const saslDefaultServiceName; // Field whose value should be set to true if the field in saslCommandPasswordFieldName needs to // be digested. extern MONGO_CLIENT_API const char* const saslCommandDigestPasswordFieldName; } mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_authenticate_impl.cpp000066400000000000000000000225211273231111400301310ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This module implements the client side of SASL authentication in MongoDB, in terms of the Cyrus * SASL library. See and http://cyrusimap.web.cmu.edu/ for relevant documentation. * * The primary entry point at runtime is saslClientAuthenticateImpl(). */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include #include #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/client/sasl_client_session.h" #include "mongo/platform/cstdint.h" #include "mongo/util/base64.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/password_digest.h" namespace mongo { using std::endl; namespace { // Default log level on the client for SASL log messages. const int defaultSaslClientLogLevel = 4; const char* const saslClientLogFieldName = "clientLogLevel"; int getSaslClientLogLevel(const BSONObj& saslParameters) { int saslLogLevel = defaultSaslClientLogLevel; BSONElement saslLogElement = saslParameters[saslClientLogFieldName]; if (saslLogElement.trueValue()) saslLogLevel = 1; if (saslLogElement.isNumber()) saslLogLevel = saslLogElement.numberInt(); return saslLogLevel; } /** * Gets the password data from "saslParameters" and stores it to "outPassword". * * If "digestPassword" indicates that the password needs to be "digested" via * mongo::createPasswordDigest(), this method takes care of that. * On success, the value of "*outPassword" is always the correct value to set * as the password on the SaslClientSession. * * Returns Status::OK() on success, and ErrorCodes::NoSuchKey if the password data is not * present in "saslParameters". Other ErrorCodes returned indicate other errors. */ Status extractPassword(const BSONObj& saslParameters, bool digestPassword, std::string* outPassword) { std::string rawPassword; Status status = bsonExtractStringField(saslParameters, saslCommandPasswordFieldName, &rawPassword); if (!status.isOK()) return status; if (digestPassword) { std::string user; status = bsonExtractStringField(saslParameters, saslCommandUserFieldName, &user); if (!status.isOK()) return status; *outPassword = mongo::createPasswordDigest(user, rawPassword); } else { *outPassword = rawPassword; } return Status::OK(); } /** * Configures "session" to perform the client side of a SASL conversation over connection * "client". * * "saslParameters" is a BSON document providing the necessary configuration information. * * Returns Status::OK() on success. */ Status configureSession(SaslClientSession* session, DBClientWithCommands* client, const std::string& targetDatabase, const BSONObj& saslParameters) { std::string mechanism; Status status = bsonExtractStringField(saslParameters, saslCommandMechanismFieldName, &mechanism); if (!status.isOK()) return status; session->setParameter(SaslClientSession::parameterMechanism, mechanism); std::string value; status = bsonExtractStringFieldWithDefault( saslParameters, saslCommandServiceNameFieldName, saslDefaultServiceName, &value); if (!status.isOK()) return status; session->setParameter(SaslClientSession::parameterServiceName, value); status = bsonExtractStringFieldWithDefault(saslParameters, saslCommandServiceHostnameFieldName, HostAndPort(client->getServerAddress()).host(), &value); if (!status.isOK()) return status; session->setParameter(SaslClientSession::parameterServiceHostname, value); status = bsonExtractStringField(saslParameters, saslCommandUserFieldName, &value); if (!status.isOK()) return status; session->setParameter(SaslClientSession::parameterUser, value); bool digestPasswordDefault = !(targetDatabase == "$external" && mechanism == "PLAIN") && !(targetDatabase == "$external" && mechanism == "GSSAPI"); bool digestPassword; status = bsonExtractBooleanFieldWithDefault( saslParameters, saslCommandDigestPasswordFieldName, digestPasswordDefault, &digestPassword); if (!status.isOK()) return status; status = extractPassword(saslParameters, digestPassword, &value); if (status.isOK()) { session->setParameter(SaslClientSession::parameterPassword, value); } else if (!(status == ErrorCodes::NoSuchKey && targetDatabase == "$external")) { // $external users do not have passwords, hence NoSuchKey is expected return status; } return session->initialize(); } /** * Driver for the client side of a sasl authentication session, conducted synchronously over * "client". */ Status saslClientAuthenticateImpl(DBClientWithCommands* client, const BSONObj& saslParameters) { int saslLogLevel = getSaslClientLogLevel(saslParameters); std::string targetDatabase; try { Status status = bsonExtractStringFieldWithDefault( saslParameters, saslCommandUserDBFieldName, saslDefaultDBName, &targetDatabase); if (!status.isOK()) return status; } catch (const DBException& ex) { return ex.toStatus(); } std::string mechanism; Status status = bsonExtractStringField(saslParameters, saslCommandMechanismFieldName, &mechanism); if (!status.isOK()) { return status; } boost::scoped_ptr session(SaslClientSession::create(mechanism)); status = configureSession(session.get(), client, targetDatabase, saslParameters); if (!status.isOK()) return status; BSONObj saslFirstCommandPrefix = BSON(saslStartCommandName << 1 << saslCommandMechanismFieldName << session->getParameter(SaslClientSession::parameterMechanism)); BSONObj saslFollowupCommandPrefix = BSON(saslContinueCommandName << 1); BSONObj saslCommandPrefix = saslFirstCommandPrefix; BSONObj inputObj = BSON(saslCommandPayloadFieldName << ""); bool isServerDone = false; while (!session->isDone()) { std::string payload; BSONType type; status = saslExtractPayload(inputObj, &payload, &type); if (!status.isOK()) return status; LOG(saslLogLevel) << "sasl client input: " << base64::encode(payload) << endl; std::string responsePayload; status = session->step(payload, &responsePayload); if (!status.isOK()) return status; LOG(saslLogLevel) << "sasl client output: " << base64::encode(responsePayload) << endl; BSONObjBuilder commandBuilder; commandBuilder.appendElements(saslCommandPrefix); commandBuilder.appendBinData(saslCommandPayloadFieldName, int(responsePayload.size()), BinDataGeneral, responsePayload.c_str()); BSONElement conversationId = inputObj[saslCommandConversationIdFieldName]; if (!conversationId.eoo()) commandBuilder.append(conversationId); // Server versions 2.3.2 and earlier may return "ok: 1" with a non-zero "code" field, // indicating a failure. Subsequent versions should return "ok: 0" on failure with a // non-zero "code" field to indicate specific failure. In all versions, ok: 1, code: >0 // and ok: 0, code optional, indicate failure. bool ok = client->runCommand(targetDatabase, commandBuilder.obj(), inputObj); ErrorCodes::Error code = ErrorCodes::fromInt(inputObj[saslCommandCodeFieldName].numberInt()); if (!ok || code != ErrorCodes::OK) { if (code == ErrorCodes::OK) code = ErrorCodes::UnknownError; return Status(code, inputObj[saslCommandErrmsgFieldName].str()); } isServerDone = inputObj[saslCommandDoneFieldName].trueValue(); saslCommandPrefix = saslFollowupCommandPrefix; } if (!isServerDone) return Status(ErrorCodes::ProtocolError, "Client finished before server."); return Status::OK(); } MONGO_INITIALIZER(SaslClientAuthenticateFunction)(InitializerContext* context) { saslClientAuthenticate = saslClientAuthenticateImpl; return Status::OK(); } } // namespace } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(client_sasl_client_authenticate_impl) mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_conversation.cpp000066400000000000000000000014061273231111400271430ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/sasl_client_conversation.h" namespace mongo { SaslClientConversation::~SaslClientConversation(){}; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_conversation.h000066400000000000000000000040711273231111400266110ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" #include "mongo/base/string_data.h" namespace mongo { class SaslClientSession; template class StatusWith; /** * Abstract class for implementing the clent-side * of a SASL mechanism conversation. */ class SaslClientConversation { MONGO_DISALLOW_COPYING(SaslClientConversation); public: /** * Implements the client side of a SASL authentication mechanism. * * "saslClientSession" is the corresponding SASLClientSession. * "saslClientSession" must stay in scope until the SaslClientConversation's * destructor completes. * **/ explicit SaslClientConversation(SaslClientSession* saslClientSession) : _saslClientSession(saslClientSession) {} virtual ~SaslClientConversation(); /** * Performs one step of the client side of the authentication session, * consuming "inputData" and producing "*outputData". * * A return of Status::OK() indicates successful progress towards authentication. * A return of !Status::OK() indicates failed authentication * * A return of true means that the authentication process has finished. * A return of false means that the authentication process has more steps. * */ virtual StatusWith step(const StringData& inputData, std::string* outputData) = 0; protected: SaslClientSession* _saslClientSession; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_session.cpp000066400000000000000000000035461273231111400261230ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/sasl_client_session.h" #include "mongo/util/assert_util.h" namespace mongo { SaslClientSession::SaslClientSessionFactoryFn SaslClientSession::create = NULL; SaslClientSession::SaslClientSession() {} SaslClientSession::~SaslClientSession() {} void SaslClientSession::setParameter(Parameter id, const StringData& value) { fassert(16807, id >= 0 && id < numParameters); fassert(28583, value.size() < std::numeric_limits::max()); DataBuffer& buffer = _parameters[id]; buffer.size = value.size(); buffer.data.reset(new char[buffer.size + 1]); // Note that we append a terminal NUL to buffer.data, so it may be treated as a C-style // string. This is required for parameterServiceName, parameterServiceHostname, // parameterMechanism and parameterUser. value.copyTo(buffer.data.get(), true); } bool SaslClientSession::hasParameter(Parameter id) { if (id < 0 || id >= numParameters) return false; return static_cast(_parameters[id].data); } StringData SaslClientSession::getParameter(Parameter id) { if (!hasParameter(id)) return StringData(); DataBuffer& buffer = _parameters[id]; return StringData(buffer.data.get(), buffer.size); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_client_session.h000066400000000000000000000114011273231111400255550ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" #include "mongo/stdx/functional.h" namespace mongo { /** * Base class for the client side of a SASL authentication conversation. * * To use, create an instance, then use setParameter() to configure the authentication * parameters. Once all parameters are set, call initialize() to initialize the client state * machine. Finally, use repeated calls to step() to generate messages to send to the server * and process server responses. * * The required parameters vary by mechanism, but all mechanisms require parameterServiceName, * parameterServiceHostname, parameterMechanism and parameterUser. All of the required * parameters must be UTF-8 encoded strings with no embedded NUL characters. The * parameterPassword parameter is not constrained. */ class SaslClientSession { MONGO_DISALLOW_COPYING(SaslClientSession); public: typedef stdx::function SaslClientSessionFactoryFn; static SaslClientSessionFactoryFn create; /** * Identifiers of parameters used to configure a SaslClientSession. */ enum Parameter { parameterServiceName = 0, parameterServiceHostname, parameterMechanism, parameterUser, parameterPassword, numParameters // Must be last }; SaslClientSession(); virtual ~SaslClientSession(); /** * Sets the parameter identified by "id" to "value". * * The value of "id" must be one of the legal values of Parameter less than numParameters. * May be called repeatedly for the same value of "id", with the last "value" replacing * previous values. * * The session object makes and owns a copy of the data in "value". */ virtual void setParameter(Parameter id, const StringData& value); /** * Returns true if "id" identifies a parameter previously set by a call to setParameter(). */ virtual bool hasParameter(Parameter id); /** * Returns the value of a previously set parameter. * * If parameter "id" was never set, returns an empty StringData. Note that a parameter may * be explicitly set to StringData(), so use hasParameter() to distinguish those cases. * * The session object owns the storage behind the returned StringData, which will remain * valid until setParameter() is called with the same value of "id", or the session object * goes out of scope. */ virtual StringData getParameter(Parameter id); /** * Initializes a session for use. * * Call exactly once, after setting any parameters you intend to set via setParameter(). */ virtual Status initialize() = 0; /** * Takes one step of the SASL protocol on behalf of the client. * * Caller should provide data from the server side of the conversation in "inputData", or an * empty StringData() if none is available. If the client should make a response to the * server, stores the response into "*outputData". * * Returns Status::OK() on success. Any other return value indicates a failed * authentication, though the specific return value may provide insight into the cause of * the failure (e.g., ProtocolError, AuthenticationFailed). * * In the event that this method returns Status::OK(), consult the value of isDone() to * determine if the conversation has completed. When step() returns Status::OK() and * isDone() returns true, authentication has completed successfully. */ virtual Status step(const StringData& inputData, std::string* outputData) = 0; /** * Returns true if the authentication completed successfully. */ virtual bool isDone() const = 0; private: /** * Buffer object that owns data for a single parameter. */ struct DataBuffer { boost::scoped_array data; size_t size; }; /// Buffers for each of the settable parameters. DataBuffer _parameters[numParameters]; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_plain_client_conversation.cpp000066400000000000000000000032731273231111400303320ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/sasl_plain_client_conversation.h" #include "mongo/base/status_with.h" #include "mongo/bson/util/builder.h" #include "mongo/client/sasl_client_session.h" #include "mongo/util/password_digest.h" namespace mongo { SaslPLAINClientConversation::SaslPLAINClientConversation(SaslClientSession* saslClientSession) : SaslClientConversation(saslClientSession) {} SaslPLAINClientConversation::~SaslPLAINClientConversation(){}; StatusWith SaslPLAINClientConversation::step(const StringData& inputData, std::string* outputData) { // Create PLAIN message on the form: user\0user\0pwd StringBuilder sb; sb << _saslClientSession->getParameter(SaslClientSession::parameterUser).toString() << '\0' << _saslClientSession->getParameter(SaslClientSession::parameterUser).toString() << '\0' << _saslClientSession->getParameter(SaslClientSession::parameterPassword).toString(); *outputData = sb.str(); return StatusWith(true); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_plain_client_conversation.h000066400000000000000000000025311273231111400277730ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/client/sasl_client_conversation.h" namespace mongo { /** * Client side authentication session for SASL PLAIN. */ class SaslPLAINClientConversation : public SaslClientConversation { MONGO_DISALLOW_COPYING(SaslPLAINClientConversation); public: /** * Implements the client side of a SASL PLAIN mechanism session. * **/ explicit SaslPLAINClientConversation(SaslClientSession* saslClientSession); virtual ~SaslPLAINClientConversation(); virtual StatusWith step(const StringData& inputData, std::string* outputData); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_scramsha1_client_conversation.cpp000066400000000000000000000212631273231111400311100ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/sasl_scramsha1_client_conversation.h" #include #include "mongo/base/parse_number.h" #include "mongo/client/sasl_client_session.h" #include "mongo/platform/random.h" #include "mongo/util/base64.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/password_digest.h" #include "mongo/util/text.h" namespace mongo { SaslSCRAMSHA1ClientConversation::SaslSCRAMSHA1ClientConversation( SaslClientSession* saslClientSession) : SaslClientConversation(saslClientSession), _step(0), _authMessage(""), _clientNonce("") {} SaslSCRAMSHA1ClientConversation::~SaslSCRAMSHA1ClientConversation() { // clear the _saltedPassword memory memset(_saltedPassword, 0, scram::hashSize); } StatusWith SaslSCRAMSHA1ClientConversation::step(const StringData& inputData, std::string* outputData) { std::vector input = StringSplitter::split(inputData.toString(), ","); _step++; switch (_step) { case 1: return _firstStep(outputData); case 2: // Append server-first-message to _authMessage _authMessage += inputData.toString() + ","; return _secondStep(input, outputData); case 3: return _thirdStep(input, outputData); default: return StatusWith(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Invalid SCRAM-SHA-1 authentication step: " << _step); } } /* * RFC 5802 specifies that in SCRAM user names characters ',' and '=' are encoded as * =2C and =3D respectively. */ static void encodeSCRAMUsername(std::string& user) { boost::replace_all(user, "=", "=3D"); boost::replace_all(user, ",", "=2C"); } /* * Generate client-first-message of the form: * n,a=authzid,n=encoded-username,r=client-nonce */ StatusWith SaslSCRAMSHA1ClientConversation::_firstStep(std::string* outputData) { if (_saslClientSession->getParameter(SaslClientSession::parameterPassword).empty()) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Empty client password provided"); } // Create text-based nonce as base64 encoding of a binary blob of length multiple of 3 const int nonceLenQWords = 3; uint64_t binaryNonce[nonceLenQWords]; boost::scoped_ptr sr(SecureRandom::create()); binaryNonce[0] = sr->nextInt64(); binaryNonce[1] = sr->nextInt64(); binaryNonce[2] = sr->nextInt64(); std::string user = _saslClientSession->getParameter(SaslClientSession::parameterUser).toString(); encodeSCRAMUsername(user); std::string clientNonce = base64::encode(reinterpret_cast(binaryNonce), sizeof(binaryNonce)); // Append client-first-message-bare to authMessage _authMessage = "n=" + user + ",r=" + clientNonce + ","; StringBuilder sb; sb << "n,,n=" << user << ",r=" << clientNonce; *outputData = sb.str(); return StatusWith(false); } /** * Parse server-first-message on the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=ClientProof * **/ StatusWith SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector& input, std::string* outputData) { if (input.size() != 3) { return StatusWith( ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect number of arguments for first SCRAM-SHA-1 server message, got " << input.size() << " expected 3"); } else if (!str::startsWith(input[0], "r=") || input[0].size() < 2) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 client|server nonce: " << input[0]); } else if (!str::startsWith(input[1], "s=") || input[1].size() < 6) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 salt: " << input[1]); } else if (!str::startsWith(input[2], "i=") || input[2].size() < 3) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 iteration count: " << input[2]); } std::string nonce = input[0].substr(2); if (!str::startsWith(nonce, _clientNonce)) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Server SCRAM-SHA-1 nonce does not match client nonce" << input[2]); } std::string salt = input[1].substr(2); int iterationCount; Status status = parseNumberFromStringWithBase(input[2].substr(2), 10, &iterationCount); if (status != Status::OK()) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Failed to parse SCRAM-SHA-1 iteration count: " << input[2]); } // Append client-final-message-without-proof to _authMessage _authMessage += "c=biws,r=" + nonce; std::string decodedSalt; try { decodedSalt = base64::decode(salt); } catch (const DBException& ex) { return StatusWith(ex.toStatus()); } scram::generateSaltedPassword( _saslClientSession->getParameter(SaslClientSession::parameterPassword), reinterpret_cast(decodedSalt.c_str()), decodedSalt.size(), iterationCount, _saltedPassword); std::string clientProof = scram::generateClientProof(_saltedPassword, _authMessage); StringBuilder sb; sb << "c=biws,r=" << nonce << ",p=" << clientProof; *outputData = sb.str(); return StatusWith(false); } /** * Verify server-final-message on the form: * v=ServerSignature * * or failed authentication server-final-message on the form: * e=message **/ StatusWith SaslSCRAMSHA1ClientConversation::_thirdStep(const std::vector& input, std::string* outputData) { if (input.size() != 1) { return StatusWith( ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect number of arguments for final SCRAM-SHA-1 server message, got " << input.size() << " expected 1"); } else if (input[0].size() < 3) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 server message length: " << input[0]); } else if (str::startsWith(input[0], "e=")) { return StatusWith(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "SCRAM-SHA-1 authentication failure: " << input[0].substr(2)); } else if (!str::startsWith(input[0], "v=")) { return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 ServerSignature: " << input[0]); } bool validServerSignature = scram::verifyServerSignature(_saltedPassword, _authMessage, input[0].substr(2)); if (!validServerSignature) { *outputData = "e=Invalid server signature"; return StatusWith( ErrorCodes::BadValue, mongoutils::str::stream() << "Client failed to verify SCRAM-SHA-1 ServerSignature, received " << input[0].substr(2)); } *outputData = ""; return StatusWith(true); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_scramsha1_client_conversation.h000066400000000000000000000043621273231111400305560ustar00rootroot00000000000000/* * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/base/string_data.h" #include "mongo/client/sasl_client_conversation.h" #include "mongo/crypto/mechanism_scram.h" namespace mongo { /** * Client side authentication session for SASL PLAIN. */ class SaslSCRAMSHA1ClientConversation : public SaslClientConversation { MONGO_DISALLOW_COPYING(SaslSCRAMSHA1ClientConversation); public: /** * Implements the client side of a SASL PLAIN mechanism session. **/ explicit SaslSCRAMSHA1ClientConversation(SaslClientSession* saslClientSession); virtual ~SaslSCRAMSHA1ClientConversation(); /** * Takes one step in a SCRAM-SHA-1 conversation. * * @return !Status::OK() for failure. The boolean part indicates if the * authentication conversation is finished or not. * **/ virtual StatusWith step(const StringData& inputData, std::string* outputData); private: /** * Generates client-first-message. **/ StatusWith _firstStep(std::string* outputData); /** * Parses server-first-message and generate client-final-message. **/ StatusWith _secondStep(const std::vector& input, std::string* outputData); /** * Generates client-first-message. **/ StatusWith _thirdStep(const std::vector& input, std::string* outputData); int _step; std::string _authMessage; unsigned char _saltedPassword[scram::hashSize]; // client and server nonce concatenated std::string _clientNonce; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/sasl_sspi.cpp000066400000000000000000000443421273231111400240570ustar00rootroot00000000000000/* * Copyright (C) 2013 10gen, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/base/init.h" #ifdef _WIN32 #define SECURITY_WIN32 1 // Required for SSPI support. #include "mongo/platform/basic.h" #include #include #include #include #include "mongo/util/mongoutils/str.h" #include "mongo/base/status.h" #include "mongo/util/scopeguard.h" #include "mongo/util/text.h" extern "C" int plain_client_plug_init(const sasl_utils_t* utils, int maxversion, int* out_version, sasl_client_plug_t** pluglist, int* plugcount); extern "C" int crammd5_client_plug_init(const sasl_utils_t* utils, int maxversion, int* out_version, sasl_client_plug_t** pluglist, int* plugcount); namespace mongo { namespace { /* * SSPI client plugin impl */ // The SSPI plugin implements the GSSAPI interface. char sspiPluginName[] = "GSSAPI"; // This structure is passed through each callback to us by the sasl glue code. struct SspiConnContext { CredHandle cred; bool haveCred; CtxtHandle ctx; bool haveCtxt; bool authComplete; std::wstring nameToken; std::string userPlusRealm; SspiConnContext() : haveCred(false), haveCtxt(false), authComplete(false) {} ~SspiConnContext() { if (haveCtxt) { DeleteSecurityContext(&ctx); } if (haveCred) { FreeCredentialsHandle(&cred); } } }; // Utility function for fetching error text from Windows API function calls. void HandleLastError(const sasl_utils_t* utils, DWORD errCode, const char* msg) { char* err; if (!FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&err, 0, NULL)) { return; } std::string buffer(mongoutils::str::stream() << "SSPI: " << msg << ": " << err); utils->seterror(utils->conn, 0, "%s", buffer.c_str()); LocalFree(err); } int sspiClientMechNew(void* glob_context, sasl_client_params_t* cparams, void** conn_context) throw() { // Prepare auth identity to pass to AcquireCredentialsHandle SEC_WINNT_AUTH_IDENTITY authIdentity; authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; // Fetch username@realm. sasl_getsimple_t* user_cb; void* user_context; int ret = cparams->utils->getcallback( cparams->utils->conn, SASL_CB_USER, (sasl_callback_ft*)&user_cb, &user_context); if (ret != SASL_OK) { cparams->utils->seterror(cparams->utils->conn, 0, "getcallback user failed"); return ret; } const char* rawUserPlusRealm; unsigned rawUserPlusRealmLength = 0; ret = user_cb(user_context, SASL_CB_USER, &rawUserPlusRealm, &rawUserPlusRealmLength); if (ret != SASL_OK) { cparams->utils->seterror(cparams->utils->conn, 0, "user callback failed"); return ret; } std::string userPlusRealm(rawUserPlusRealm, rawUserPlusRealmLength); // Parse out the username and realm. size_t atSign = userPlusRealm.find('@'); if (atSign == std::string::npos) { cparams->utils->seterror(cparams->utils->conn, 0, "no @REALM found in username"); return SASL_BADPARAM; } std::string utf8Username(userPlusRealm, 0, atSign); std::wstring utf16Username(toWideString(utf8Username.c_str())); authIdentity.UserLength = utf16Username.length(); authIdentity.User = reinterpret_cast(const_cast(utf16Username.c_str())); std::string utf8Domain(userPlusRealm, atSign + 1); std::wstring utf16Domain(toWideString(utf8Domain.c_str())); authIdentity.DomainLength = utf16Domain.length(); authIdentity.Domain = reinterpret_cast(const_cast(utf16Domain.c_str())); // Fetch password, if available. authIdentity.PasswordLength = 0; authIdentity.Password = NULL; std::wstring utf16Password; sasl_secret_t* password = NULL; sasl_getsecret_t* pass_cb; void* pass_context; ret = cparams->utils->getcallback( cparams->utils->conn, SASL_CB_PASS, (sasl_callback_ft*)&pass_cb, &pass_context); if ((ret == SASL_OK) && pass_cb) { ret = pass_cb(cparams->utils->conn, pass_context, SASL_CB_PASS, &password); if ((ret == SASL_OK) && password) { std::string utf8Password(reinterpret_cast(password->data), password->len); utf16Password = toWideString(utf8Password.c_str()); authIdentity.PasswordLength = utf16Password.length(); authIdentity.Password = reinterpret_cast(const_cast(utf16Password.c_str())); } } // Actually acquire the handle to the client credentials. std::auto_ptr pcctx(new SspiConnContext()); pcctx->userPlusRealm = userPlusRealm; TimeStamp ignored; SECURITY_STATUS status = AcquireCredentialsHandleW(NULL, // principal L"kerberos", SECPKG_CRED_OUTBOUND, NULL, // LOGON id &authIdentity, // auth data NULL, // get key fn NULL, // get key arg &pcctx->cred, &ignored); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "AcquireCredentialsHandle"); return SASL_FAIL; } pcctx->haveCred = true; // Compose target name token. if (cparams->serverFQDN == NULL || strlen(cparams->serverFQDN) == 0) { cparams->utils->seterror(cparams->utils->conn, 0, "SSPI: no serverFQDN"); return SASL_FAIL; } pcctx->nameToken = toWideString((std::string(cparams->service) + "/" + cparams->serverFQDN).c_str()); *conn_context = pcctx.release(); return SASL_OK; } int sspiValidateServerSecurityLayerOffering(SspiConnContext* pcctx, sasl_client_params_t* cparams, const char* serverin, unsigned serverinlen) { boost::scoped_array message(new char[serverinlen]); memcpy(message.get(), serverin, serverinlen); SecBuffer wrapBufs[2]; SecBufferDesc wrapBufDesc; wrapBufDesc.cBuffers = 2; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = serverinlen; wrapBufs[0].BufferType = SECBUFFER_STREAM; wrapBufs[0].pvBuffer = message.get(); wrapBufs[1].cbBuffer = 0; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = NULL; SECURITY_STATUS status = DecryptMessage(&pcctx->ctx, &wrapBufDesc, 0, NULL); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "DecryptMessage"); return SASL_FAIL; } // Validate the server's plaintext message. // Length (as per RFC 4752) if (wrapBufs[1].cbBuffer < 4) { cparams->utils->seterror(cparams->utils->conn, 0, "SSPI: server message is too short"); return SASL_FAIL; } // First bit of first byte set, indicating that the client may elect to use no // security layer. As a client we are uninterested in any of the other features the // server offers and thus we ignore the other bits. if (!(static_cast(wrapBufs[1].pvBuffer)[0] & 1)) { cparams->utils->seterror( cparams->utils->conn, 0, "SSPI: server does not support the required security layer"); return SASL_BADAUTH; } return SASL_OK; } int sspiSendClientAuthzId(SspiConnContext* pcctx, sasl_client_params_t* cparams, const char* serverin, unsigned serverinlen, const char** clientout, unsigned* clientoutlen, sasl_out_params_t* oparams) { // Ensure server response is decryptable. int decryptStatus = sspiValidateServerSecurityLayerOffering(pcctx, cparams, serverin, serverinlen); if (decryptStatus != SASL_OK) { return decryptStatus; } // Fill in AUTHID and AUTHZID fields in oparams. int ret = cparams->canon_user(cparams->utils->conn, pcctx->userPlusRealm.c_str(), 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); // Reply to server with security capability and authz name. SecPkgContext_Sizes sizes; SECURITY_STATUS status = QueryContextAttributes(&pcctx->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "QueryContextAttributes(sizes)"); return SASL_FAIL; } // See RFC4752. int plaintextMessageSize = 4 + pcctx->userPlusRealm.size(); boost::scoped_array message( new char[sizes.cbSecurityTrailer + plaintextMessageSize + sizes.cbBlockSize]); char* plaintextMessage = message.get() + sizes.cbSecurityTrailer; plaintextMessage[0] = 1; // LAYER_NONE plaintextMessage[1] = 0; plaintextMessage[2] = 0; plaintextMessage[3] = 0; memcpy(&plaintextMessage[4], pcctx->userPlusRealm.c_str(), pcctx->userPlusRealm.size()); SecBuffer wrapBufs[3]; SecBufferDesc wrapBufDesc; wrapBufDesc.cBuffers = 3; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; wrapBufs[0].BufferType = SECBUFFER_TOKEN; wrapBufs[0].pvBuffer = message.get(); wrapBufs[1].cbBuffer = plaintextMessageSize; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = message.get() + sizes.cbSecurityTrailer; wrapBufs[2].cbBuffer = sizes.cbBlockSize; wrapBufs[2].BufferType = SECBUFFER_PADDING; wrapBufs[2].pvBuffer = message.get() + sizes.cbSecurityTrailer + plaintextMessageSize; status = EncryptMessage(&pcctx->ctx, SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "EncryptMessage"); return SASL_FAIL; } // Create the message to send to server. *clientoutlen = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; char* newoutbuf = static_cast(cparams->utils->malloc(*clientoutlen)); memcpy(newoutbuf, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); *clientout = newoutbuf; return SASL_OK; } int sspiClientMechStep(void* conn_context, sasl_client_params_t* cparams, const char* serverin, unsigned serverinlen, sasl_interact_t** prompt_need, const char** clientout, unsigned* clientoutlen, sasl_out_params_t* oparams) throw() { SspiConnContext* pcctx = static_cast(conn_context); *clientout = NULL; *clientoutlen = 0; if (pcctx->authComplete) { return sspiSendClientAuthzId( pcctx, cparams, serverin, serverinlen, clientout, clientoutlen, oparams); } SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; if (pcctx->haveCtxt) { // If we already have a context, we now have data to send. // Put this data in an inbuf. inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = const_cast(serverin); inBufs[0].cbBuffer = serverinlen; inBufs[0].BufferType = SECBUFFER_TOKEN; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; ULONG contextAttr = 0; SECURITY_STATUS status = InitializeSecurityContextW(&pcctx->cred, pcctx->haveCtxt ? &pcctx->ctx : NULL, const_cast(pcctx->nameToken.c_str()), ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH, 0, SECURITY_NETWORK_DREP, (pcctx->haveCtxt ? &inbuf : NULL), 0, &pcctx->ctx, &outbuf, &contextAttr, NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { HandleLastError(cparams->utils, status, "InitializeSecurityContext"); return SASL_FAIL; } ON_BLOCK_EXIT(FreeContextBuffer, outbuf.pBuffers[0].pvBuffer); pcctx->haveCtxt = true; if (status == SEC_E_OK) { // Send back nothing and wait for the server to reply with the security capabilities *clientout = NULL; *clientoutlen = 0; pcctx->authComplete = true; return SASL_CONTINUE; } char* newoutbuf = static_cast(cparams->utils->malloc(outBufs[0].cbBuffer)); *clientoutlen = outBufs[0].cbBuffer; memcpy(newoutbuf, outBufs[0].pvBuffer, *clientoutlen); *clientout = newoutbuf; return SASL_CONTINUE; } void sspiClientMechDispose(void* conn_context, const sasl_utils_t* utils) { SspiConnContext* pcctx = static_cast(conn_context); delete pcctx; } void sspiClientMechFree(void* glob_context, const sasl_utils_t* utils) {} sasl_client_plug_t sspiClientPlugin[] = { {sspiPluginName, /* mechanism name */ 112, /* TODO: (taken from gssapi) best mech additional security layer strength factor */ SASL_SEC_NOPLAINTEXT /* eam: copied from gssapi */ | SASL_SEC_NOACTIVE | SASL_SEC_NOANONYMOUS | SASL_SEC_MUTUAL_AUTH | SASL_SEC_PASS_CREDENTIALS, /* security_flags */ SASL_FEAT_NEEDSERVERFQDN | SASL_FEAT_WANT_CLIENT_FIRST | SASL_FEAT_ALLOWS_PROXY, NULL, /* required prompt ids, NULL = user/pass only */ NULL, /* global state for mechanism */ sspiClientMechNew, sspiClientMechStep, sspiClientMechDispose, sspiClientMechFree, NULL, NULL, NULL}}; int sspiClientPluginInit(const sasl_utils_t* utils, int max_version, int* out_version, sasl_client_plug_t** pluglist, int* plugcount) { if (max_version < SASL_CLIENT_PLUG_VERSION) { utils->seterror(utils->conn, 0, "Wrong SSPI version"); return SASL_BADVERS; } *out_version = SASL_CLIENT_PLUG_VERSION; *pluglist = sspiClientPlugin; *plugcount = 1; return SASL_OK; } /** * Registers the plugin at process initialization time. * Must be run after the AllocatorsAndMutexes are registered, but before the ClientContext is * created. */ MONGO_INITIALIZER_WITH_PREREQUISITES(SaslSspiClientPlugin, ("CyrusSaslAllocatorsAndMutexes", "CyrusSaslClientContext")) (InitializerContext*) { int ret = sasl_client_add_plugin(sspiPluginName, sspiClientPluginInit); if (SASL_OK != ret) { return Status(ErrorCodes::UnknownError, mongoutils::str::stream() << "could not add SASL Client SSPI plugin " << sspiPluginName << ": " << sasl_errstring(ret, NULL, NULL)); } return Status::OK(); } MONGO_INITIALIZER_WITH_PREREQUISITES(SaslCramClientPlugin, ("CyrusSaslAllocatorsAndMutexes", "CyrusSaslClientContext")) (InitializerContext*) { int ret = sasl_client_add_plugin("CRAMMD5", crammd5_client_plug_init); if (SASL_OK != ret) { return Status(ErrorCodes::UnknownError, mongoutils::str::stream() << "Could not add SASL Client CRAM-MD5 plugin " << sspiPluginName << ": " << sasl_errstring(ret, NULL, NULL)); } return Status::OK(); } MONGO_INITIALIZER_WITH_PREREQUISITES(SaslPlainClientPlugin, ("CyrusSaslAllocatorsAndMutexes", "CyrusSaslClientContext")) (InitializerContext*) { int ret = sasl_client_add_plugin("PLAIN", plain_client_plug_init); if (SASL_OK != ret) { return Status(ErrorCodes::UnknownError, mongoutils::str::stream() << "Could not add SASL Client PLAIN plugin " << sspiPluginName << ": " << sasl_errstring(ret, NULL, NULL)); } return Status::OK(); } } // namespace } // namespace mongo #endif // ifdef _WIN32 MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(client_sasl_sspi) mongo-cxx-driver-legacy-1.1.2/src/mongo/client/undef_macros.h000066400000000000000000000027551273231111400241730ustar00rootroot00000000000000/** @file undef_macros.h remove mongo implementation macros after using */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // If you define a new global un-prefixed macro, please add it here and in redef_macros // #pragma once // this file is intended to be processed multiple times #ifdef MONGO_MACROS_PUSHED #if defined(_WIN32) #pragma pop_macro("min") #pragma pop_macro("max") #pragma pop_macro("NOMINMAX") #endif // bson/inline_decls.h #undef NOINLINE_DECL #pragma pop_macro("NOINLINE_DECL") #undef PACKED_DECL #pragma pop_macro("PACKED_DECL") // util/assert_util.h #undef wassert #pragma pop_macro("wassert") #undef massert #pragma pop_macro("massert") #undef uassert #pragma pop_macro("uassert") #undef verify #pragma pop_macro("verify") #undef invariant #pragma pop_macro("invariant") #undef invariantOK #pragma pop_macro("invariantOK") #undef DESTRUCTOR_GUARD #pragma pop_macro("DESTRUCTOR_GUARD") #undef MONGO_MACROS_PUSHED #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/client/update_write_operation.cpp000066400000000000000000000051171273231111400266300ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/update_write_operation.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/write_options.h" #include "mongo/db/namespace_string.h" namespace mongo { namespace { const char kCommandKey[] = "update"; const char kBatchName[] = "updates"; const char kSelectorKey[] = "q"; const char kUpdateKey[] = "u"; const char kMultiKey[] = "multi"; const char kUpsertKey[] = "upsert"; } // namespace UpdateWriteOperation::UpdateWriteOperation(const BSONObj& selector, const BSONObj& update, int flags) : _selector(selector), _update(update), _flags(flags) {} WriteOpType UpdateWriteOperation::operationType() const { return dbWriteUpdate; } const char* UpdateWriteOperation::batchName() const { return kBatchName; } int UpdateWriteOperation::incrementalSize() const { return _selector.objsize() + _update.objsize(); } void UpdateWriteOperation::startRequest(const std::string& ns, bool, BufBuilder* builder) const { builder->appendNum(0); builder->appendStr(ns); builder->appendNum(_flags); } void UpdateWriteOperation::appendSelfToRequest(BufBuilder* builder) const { _selector.appendSelfToBufBuilder(*builder); _update.appendSelfToBufBuilder(*builder); } void UpdateWriteOperation::startCommand(const std::string& ns, BSONObjBuilder* command) const { command->append(kCommandKey, nsToCollectionSubstring(ns)); } void UpdateWriteOperation::appendSelfToCommand(BSONArrayBuilder* batch) const { BSONObjBuilder updateBuilder; appendSelfToBSONObj(&updateBuilder); batch->append(updateBuilder.obj()); } void UpdateWriteOperation::appendSelfToBSONObj(BSONObjBuilder* obj) const { obj->append(kSelectorKey, _selector); obj->append(kUpdateKey, _update); obj->append(kMultiKey, bool(_flags & UpdateOption_Multi)); obj->append(kUpsertKey, bool(_flags & UpdateOption_Upsert)); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/update_write_operation.h000066400000000000000000000027071273231111400262770ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/write_operation_base.h" namespace mongo { class UpdateWriteOperation : public WriteOperationBase { public: UpdateWriteOperation(const BSONObj& selector, const BSONObj& update, int flags); virtual WriteOpType operationType() const; virtual const char* batchName() const; virtual int incrementalSize() const; virtual void startRequest(const std::string& ns, bool ordered, BufBuilder* builder) const; virtual void appendSelfToRequest(BufBuilder* builder) const; virtual void startCommand(const std::string& ns, BSONObjBuilder* command) const; virtual void appendSelfToCommand(BSONArrayBuilder* batch) const; virtual void appendSelfToBSONObj(BSONObjBuilder* obj) const; private: const BSONObj _selector; const BSONObj _update; const int _flags; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/wire_protocol_writer.cpp000066400000000000000000000147101273231111400263360ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/wire_protocol_writer.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/write_result.h" #include "mongo/db/namespace_string.h" namespace mongo { WireProtocolWriter::WireProtocolWriter(DBClientBase* client) : _client(client) {} void WireProtocolWriter::write(const StringData& ns, const std::vector& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult) { if (_client->getMaxWireVersion() >= 4) { // Per DRIVERS-250: // If your driver sends unacknowledged writes using op codes (OP_INSERT, OP_UPDATE, // OP_DELETE), you MUST raise an error when bypassDocumentValidation is explicitly set by a // user on >= 3.2 servers. // uassert(0, "bypassDocumentValidation is not supported for unacknowledged writes with MongoDB " "3.2 and later.", !bypassDocumentValidation); } // Effectively a map of batch relative indexes to WriteOperations std::vector batchOps; BufBuilder builder; std::vector::const_iterator batch_begin = write_operations.begin(); const std::vector::const_iterator end = write_operations.end(); while (batch_begin != end) { std::vector::const_iterator batch_iter = batch_begin; // We must be able to fit the first item of the batch. Otherwise, the calling code // passed an over size write operation in violation of our contract. invariant(_fits(&builder, *batch_iter)); // Set the current operation type for this batch const WriteOpType batchOpType = (*batch_iter)->operationType(); // Begin the command for this batch. (*batch_iter)->startRequest(ns.toString(), ordered, &builder); while (true) { // Always safe to append here: either we just entered the loop, or all the // below checks passed. (*batch_iter)->appendSelfToRequest(&builder); // Associate batch index with WriteOperation batchOps.push_back(*batch_iter); // If the operation we just queued isn't batchable, issue what we have. if (!_batchableRequest(batchOpType, writeResult)) break; // Peek at the next operation. const std::vector::const_iterator next = boost::next(batch_iter); // If we are out of operations, issue what we have. if (next == end) break; // If the next operation is of a different type, issue what we have. if ((*next)->operationType() != batchOpType) break; // If adding the next op would put us over the limit of ops in a batch, issue // what we have. if (std::distance(batch_begin, next) >= _client->getMaxWriteBatchSize()) break; // If we can't put the next item into the current batch, issue what we have. if (!_fits(&builder, *next)) break; // OK to proceed to next op batch_iter = next; } // Issue the complete command. BSONObj batchResult = _send(batchOpType, builder, writeConcern, ns); // Merge this batch's result into the result for all batches written. writeResult->_mergeGleResult(batchOps, batchResult); batchOps.clear(); // Check write result for errors if we are doing ordered processing or last op bool lastOp = *batch_iter == write_operations.back(); if (ordered || lastOp) writeResult->_check(lastOp); // Reset the builder so we can build the next request. builder.reset(); // The next batch begins with the op after the last one in the just issued batch. batch_begin = ++batch_iter; } } bool WireProtocolWriter::_fits(BufBuilder* builder, WriteOperation* op) { return (builder->len() + op->incrementalSize()) <= _client->getMaxMessageSizeBytes(); } BSONObj WireProtocolWriter::_send(WriteOpType opCode, const BufBuilder& builder, const WriteConcern* writeConcern, const StringData& ns) { Message request; request.setData(opCode, builder.buf(), builder.len()); _client->say(request); BSONObj result; if (writeConcern->requiresConfirmation()) { BSONObjBuilder bob; bob.append("getlasterror", true); bob.appendElements(writeConcern->obj()); bool commandWorked = _client->runCommand(nsToDatabase(ns), bob.obj(), result); if (!commandWorked) throw OperationException(result); } return result; } bool WireProtocolWriter::_batchableRequest(WriteOpType opCode, const WriteResult* const writeResult) { /* * In order to get detailed write information using the legacy MongoDB wire protocol * you must send individual messages for each write. Inserts are the only type of write * that is batchable using the wire protocol so we must take care to only batch them * if and only if we do not require detailed insert results. * * As an example: Legacy inserts of a vector of BSONObj do not require detailed insert * results and should be performed in a batch to increase performance. However, bulk * operations require detailed results and thus must be executed serially when using * the wire protocol. */ return (opCode == dbWriteInsert && !(writeResult->_requiresDetailedInsertResults)); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/wire_protocol_writer.h000066400000000000000000000030031273231111400257740ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclient_writer.h" namespace mongo { class DBClientBase; class WireProtocolWriter : public DBClientWriter { public: explicit WireProtocolWriter(DBClientBase* client); virtual void write(const StringData& ns, const std::vector& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult); private: BSONObj _send(WriteOpType opCode, const BufBuilder& builder, const WriteConcern* wc, const StringData& ns); bool _batchableRequest(WriteOpType opCode, const WriteResult* const writeResult); bool _fits(BufBuilder* builder, WriteOperation* operation); DBClientBase* const _client; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_concern.cpp000066400000000000000000000077171273231111400247250ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/write_concern.h" #include "mongo/util/assert_util.h" namespace mongo { const char WriteConcern::kMajority[] = "majority"; const WriteConcern WriteConcern::unacknowledged = WriteConcern().nodes(0); const WriteConcern WriteConcern::acknowledged = WriteConcern(); const WriteConcern WriteConcern::journaled = WriteConcern().journal(true); const WriteConcern WriteConcern::replicated = WriteConcern().nodes(2); const WriteConcern WriteConcern::majority = WriteConcern().mode(kMajority); /** * The default constructor sets _w to 1 and the _enabled bit for _w to zero. * * The enabled bit must be unset by default because we should not send the w * parameter to the server unless it has been explicity set. * * If the _w bit were enabled by default it would be serialized with the gle * message and overwrite the server side default write concern. * * The private member _w is set to 1 because the default (simply sending GLE) * is logically equivalent to requiring confirmation from a single node. Upon * being set by the user via nodes() or mode() it overrides the default value * and is sent to the server. * * See DRIVERS-131 for more information: * https://jira.mongodb.org/browse/drivers-131 */ WriteConcern::WriteConcern() : _enabled(), _w(1), _w_str(), _j(false), _fsync(false), _timeout(0) {} int32_t WriteConcern::nodes() const { invariant(_enabled.test(kW) || (!_enabled.test(kWStr))); return _w; } const std::string& WriteConcern::mode() const { invariant(_enabled.test(kWStr)); return _w_str; } bool WriteConcern::journal() const { return _j; } bool WriteConcern::fsync() const { return _fsync; } int32_t WriteConcern::timeout() const { return _timeout; } WriteConcern& WriteConcern::nodes(int w) { _w = w; _enabled.set(kW); _enabled.reset(kWStr); return *this; } WriteConcern& WriteConcern::mode(const StringData& w) { _w_str = w.toString(); _enabled.set(kWStr); _enabled.reset(kW); return *this; } WriteConcern& WriteConcern::journal(bool j) { _j = j; _enabled.set(kJ); return *this; } WriteConcern& WriteConcern::fsync(bool fsync) { _fsync = fsync; _enabled.set(kFsync); return *this; } WriteConcern& WriteConcern::timeout(int timeout) { _timeout = timeout; _enabled.set(kTimeout); return *this; } /** * The only time we don't require confirmation is when w is explicitly set to 0. * See DRIVERS-131 for more information: https://jira.mongodb.org/browse/DRIVERS-131 */ bool WriteConcern::requiresConfirmation() const { return !_enabled.test(kW) || _w != 0; } bool WriteConcern::hasMode() const { return _enabled.test(kWStr); } /** * Only append options if they have explicitly been set to avoid overwriting server * side defaults. * See DRIVERS-131 for more information: https://jira.mongodb.org/browse/DRIVERS-131 */ BSONObj WriteConcern::obj() const { BSONObjBuilder write_concern; if (_enabled.test(kW)) write_concern.append("w", _w); if (_enabled.test(kWStr)) write_concern.append("w", _w_str); if (_enabled.test(kJ)) write_concern.append("j", _j); if (_enabled.test(kFsync)) write_concern.append("fsync", _fsync); if (_enabled.test(kTimeout)) write_concern.append("wtimeout", _timeout); return write_concern.obj(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_concern.h000066400000000000000000000112401273231111400243540ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" namespace mongo { /** * Class to encapsulate client side "Write Concern" concept. * * Write concern describes the guarantee that MongoDB provides when reporting * on the success of a write operation. * * Example usage: * WriteConcern wc = WriteConcern().nodes(3).journal(false); */ class MONGO_CLIENT_API WriteConcern { public: /** Default write concern: equivalent to acknowledged */ WriteConcern(); /** * Using nodes(kMajority) confirms that write operations have propagated * to the majority of a replica set. This allows you to avoid hard coding * assumptions about the size of your replica set into your application. */ static const char kMajority[]; // // Standard write concern levels as defined in the MongoDB manual: // http://docs.mongodb.org/manual/core/write-concern/ // /** Fire and forget */ static const WriteConcern unacknowledged; /** A single node acknowledges the write, equivalent to default constructor */ static const WriteConcern acknowledged; /** A single node acknowledges the write operation was committed to journal */ static const WriteConcern journaled; /** Two nodes have acknowledged receipt of the write operation */ static const WriteConcern replicated; /** A majority of nodes acknowledges (replica set) */ static const WriteConcern majority; /** * Returns an integer representing the number of nodes required for write * to be considered successful. * * If set this becomes the "w" parameter when sent to the server. * * @return number of nodes required */ int32_t nodes() const; /** * Returns a string representing the write concern mode. * * If set this becomes the "w" parameter when sent to the server. * * @return nodes required as std::string */ const std::string& mode() const; /** * If write will only be considered successful when committed to journal. * * @return true if write will block on MongoDB journal */ bool journal() const; /** * If fsync is set and the server is running without journaling, * the write will only be considered successful when the server has synced * all data files to disk. If the server is running with journaling, this acts * the same as if journal() was set. Cannot be used in combination with journal(true). * * @return true if the fsync option is set on the write. */ bool fsync() const; /** * Length of time to block waiting for nodes, journal, or fsync. * * @return int representing milliseconds to wait for write */ int32_t timeout() const; /** Sets the number of nodes required for write to be successful. */ WriteConcern& nodes(int w); /** Sets the type of nodes required for write to be successful. */ WriteConcern& mode(const StringData& w); /** Sets whether journal is required for write to be successful. */ WriteConcern& journal(bool j); /** * Sets the value of the fsync parameter. * * @note The behavior of this option is dependent on server configuration. * @see The comment on fsync() for details. */ WriteConcern& fsync(bool fsync); /** Sets timeout to wait for write to be successful. */ WriteConcern& timeout(int timeout); /** Whether we need to send getLastError for this WriteConcern */ bool requiresConfirmation() const; /** Whether the write concern currently reflects a mode */ bool hasMode() const; /** Turn write concern into an object for inclusion in GetLastError or write command */ BSONObj obj() const; private: // Enabled option book keeping static const size_t kNumOptions = 5; enum Options { kW, kWStr, kJ, kFsync, kTimeout }; std::bitset _enabled; // Actual option values int32_t _w; std::string _w_str; bool _j; bool _fsync; int32_t _timeout; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_concern_test.cpp000066400000000000000000000070361273231111400257560ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/write_concern.h" #include "mongo/unittest/unittest.h" namespace mongo { using std::string; TEST(WriteConcern, Defaults) { WriteConcern wc; ASSERT_FALSE(wc.hasMode()); ASSERT_EQUALS(wc.nodes(), 1); ASSERT_FALSE(wc.journal()); ASSERT_FALSE(wc.fsync()); ASSERT_EQUALS(wc.timeout(), 0); } TEST(WriteConcern, Chain) { WriteConcern wc = WriteConcern().nodes(2).journal(true); ASSERT_EQUALS(wc.nodes(), 2); ASSERT_FALSE(wc.hasMode()); ASSERT_TRUE(wc.journal()); // should be defaults ASSERT_FALSE(wc.fsync()); ASSERT_EQUALS(wc.timeout(), 0); } TEST(WriteConcern, DefaultToBSON) { BSONObj result; WriteConcern wc; ASSERT_EQUALS(wc.nodes(), 1); result = wc.obj(); ASSERT_FALSE(result.hasField("w")); ASSERT_FALSE(result.hasField("j")); ASSERT_FALSE(result.hasField("fsync")); ASSERT_FALSE(result.hasField("wtimeout")); } TEST(WriteConcern, NodesString) { BSONObj result; WriteConcern wc; wc.nodes(3); ASSERT_FALSE(wc.hasMode()); ASSERT_EQUALS(wc.nodes(), 3); result = wc.obj(); ASSERT_TRUE(result.hasField("w")); ASSERT_EQUALS(result["w"].Int(), 3); wc.mode(WriteConcern::kMajority); ASSERT_TRUE(wc.hasMode()); ASSERT_EQUALS(wc.mode(), string(WriteConcern::kMajority)); result = wc.obj(); ASSERT_TRUE(result.hasField("w")); ASSERT_EQUALS(result["w"].String(), string(WriteConcern::kMajority)); wc.nodes(5); ASSERT_FALSE(wc.hasMode()); ASSERT_EQUALS(wc.nodes(), 5); result = wc.obj(); ASSERT_TRUE(result.hasField("w")); ASSERT_EQUALS(result["w"].Int(), 5); } TEST(WriteConcern, NeedsGLE) { WriteConcern wc; ASSERT_TRUE(wc.requiresConfirmation()); wc.nodes(0); ASSERT_FALSE(wc.requiresConfirmation()); wc.nodes(3); ASSERT_TRUE(wc.requiresConfirmation()); } TEST(WriteConcern, Unacknowledged) { ASSERT_FALSE(WriteConcern::unacknowledged.requiresConfirmation()); ASSERT_EQUALS(WriteConcern::unacknowledged.nodes(), 0); ASSERT_FALSE(WriteConcern().nodes(0).requiresConfirmation()); ASSERT_FALSE(WriteConcern().nodes(0).journal(false).requiresConfirmation()); ASSERT_FALSE(WriteConcern().nodes(0).timeout(100).requiresConfirmation()); } TEST(WriteConcern, Acknowledged) { ASSERT_TRUE(WriteConcern::acknowledged.requiresConfirmation()); ASSERT_EQUALS(WriteConcern::acknowledged.nodes(), 1); } TEST(WriteConcern, Journaled) { ASSERT_TRUE(WriteConcern::journaled.requiresConfirmation()); ASSERT_TRUE(WriteConcern::journaled.journal()); } TEST(WriteConcern, Replicated) { ASSERT_TRUE(WriteConcern::replicated.requiresConfirmation()); ASSERT_EQUALS(WriteConcern::replicated.nodes(), 2); } TEST(WriteConcern, Majority) { ASSERT_TRUE(WriteConcern::majority.requiresConfirmation()); ASSERT_EQUALS(WriteConcern::majority.mode(), string(WriteConcern::kMajority)); ASSERT_TRUE(WriteConcern::majority.hasMode()); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_operation.h000066400000000000000000000100441273231111400247260ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/bson/bsonobjbuilder.h" #include "mongo/util/net/operation.h" namespace mongo { /** * Represents a single server side write operation and encapsulates * the process for encoding the operation into either a wire protocol * request message or a command. */ class WriteOperation { public: virtual ~WriteOperation() {} /** * Returns the MongoDB wire protocol operation type represented * by an instance of this particular write operation. */ virtual WriteOpType operationType() const = 0; /** * Returns the name for a batch of this type of write operation. */ virtual const char* batchName() const = 0; /** * Returns the incremental size (in bytes) required to add this write * operation to a batch. */ virtual int incrementalSize() const = 0; /** * Appends the preamble for a wire protocol message into the supplied * BufBuilder. * * This is the part of the wire protocol message after the header but * before the bson document portion. It typically contains the namespace, * flags, and potentially space reserved by the protocol for future use. * * NOTE: The size of the preamble is fixed but operation type dependant. */ virtual void startRequest(const std::string& ns, bool ordered, BufBuilder* builder) const = 0; /** * Appends a document (or documents in the case of update) which describe * the write operation represented by an instance of this class into the * supplied BufBuilder. * * This method may be called multiple times by a WireProtocolWriter in order * to batch operations of the same type into a single wire protocol request. * * NOTE: The size of this portion of the message is flexible but the size of * the message itself is bounded by the server's maxMessageSizeBytes. */ virtual void appendSelfToRequest(BufBuilder* builder) const = 0; /** * Appends the preamble for a write command into the supplied BSONObjBuilder. * * Typically this involves a single bson element having a key that represents * the operation type and a value which represents the collection to which the * operation will be applied. This write op element must be the first element * in the document according to the specification. */ virtual void startCommand(const std::string& ns, BSONObjBuilder* command) const = 0; /** * Appends a single document that describes the write operation represented by * an instance of this class into the supplied BSONArrayBuilder. * * This method will be called multiple times by a DBClientWriter in order to batch * operations of the same type into a single command. * * NOTE: The ultimate size of the of the command is bounded by the sever's * maxBsonObjectSize. */ virtual void appendSelfToCommand(BSONArrayBuilder* batch) const = 0; /** * Appends the data represented by an instance of this class to a BSONObjBuilder. */ virtual void appendSelfToBSONObj(BSONObjBuilder* obj) const = 0; /** * Sets the index of this WriteOperation in the context of a larger bulk operation. */ virtual void setBulkIndex(size_t index) = 0; /** * The index of this WriteOperation in the context of a larger bulk operation. */ virtual size_t getBulkIndex() const = 0; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_operation_base.cpp000066400000000000000000000016371273231111400262630ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/write_operation_base.h" namespace mongo { WriteOperationBase::WriteOperationBase() : _bulkIndex(0) {} void WriteOperationBase::setBulkIndex(size_t index) { _bulkIndex = index; } size_t WriteOperationBase::getBulkIndex() const { return _bulkIndex; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_operation_base.h000066400000000000000000000017031273231111400257220ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/write_operation.h" #include "mongo/platform/cstdint.h" namespace mongo { class WriteOperationBase : public WriteOperation { public: WriteOperationBase(); virtual void setBulkIndex(size_t index); virtual size_t getBulkIndex() const; private: size_t _bulkIndex; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_options.h000066400000000000000000000033641273231111400244300ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { enum UpdateOptions { /** Upsert - that is, insert the item if no matching item is found. */ UpdateOption_Upsert = 1 << 0, /** Update multiple documents (if multiple documents match query expression). (Default is update a single document and stop.) */ UpdateOption_Multi = 1 << 1, /** flag from mongo saying this update went everywhere */ UpdateOption_Broadcast = 1 << 2, // TODO: upsert, and multi are per item in a batch, this is for the whole batch /** Disables document validation for this operation. */ UpdateOption_BypassDocumentValidation = 1 << 3 }; enum RemoveOptions { /** only delete one option */ RemoveOption_JustOne = 1 << 0, /** flag from mongo saying this update went everywhere */ RemoveOption_Broadcast = 1 << 1 }; /** * need to put in DbMesssage::ReservedOptions as well */ enum InsertOptions { /** With muli-insert keep processing inserts if one fails */ InsertOption_ContinueOnError = 1 << 0, /** Disables document validation for this operation. */ InsertOption_BypassDocumentValidation = 1 << 1 }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_result.cpp000066400000000000000000000215001273231111400245760ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/write_result.h" #include "mongo/client/exceptions.h" #include "mongo/client/write_operation.h" #include "mongo/db/jsobj.h" namespace mongo { // For backwards compatibility. See MongoDB src/mongo/base/error_codes.err namespace { const int kUnknownError = 8; const int kWriteConcernErrorCode = 64; } // namespace WriteResult::WriteResult() : _nInserted(0), _nUpserted(0), _nMatched(0), _nModified(0), _nRemoved(0), _hasModifiedCount(true), _requiresDetailedInsertResults(false) {} bool WriteResult::hasErrors() const { return hasWriteErrors() || hasWriteConcernErrors(); } bool WriteResult::hasWriteErrors() const { return !_writeErrors.empty(); } bool WriteResult::hasWriteConcernErrors() const { return !_writeConcernErrors.empty(); } bool WriteResult::hasModifiedCount() const { return _hasModifiedCount; } int WriteResult::nInserted() const { return _nInserted; } int WriteResult::nUpserted() const { return _nUpserted; } int WriteResult::nMatched() const { return _nMatched; } int WriteResult::nModified() const { uassert(0, "this result does not have a modified count", _hasModifiedCount); return _nModified; } int WriteResult::nRemoved() const { return _nRemoved; } const std::vector& WriteResult::upserted() const { return _upserted; } const std::vector& WriteResult::writeErrors() const { return _writeErrors; } const std::vector& WriteResult::writeConcernErrors() const { return _writeConcernErrors; } void WriteResult::_mergeCommandResult(const std::vector& ops, const BSONObj& result) { int affected = _getIntOrDefault(result, "n"); // Handle Write Batch switch (ops.front()->operationType()) { case dbWriteInsert: _nInserted += affected; break; case dbWriteDelete: _nRemoved += affected; break; case dbWriteUpdate: if (result.hasField("upserted")) { int nUpserted = _createUpserts(result.getField("upserted"), ops); _nUpserted += nUpserted; _nMatched += (affected - nUpserted); } else { _nMatched += affected; } _setModified(result); break; } // Handle Write Errors if (result.hasField("writeErrors")) { BSONElement writeErrors = result.getField("writeErrors"); BSONObjIterator arrayIterator(writeErrors.Obj()); BSONElement current; while (arrayIterator.more()) _createWriteError(arrayIterator.next().Obj(), ops); } _mergeWriteConcern(result); } void WriteResult::_mergeWriteConcern(const BSONObj& result) { // Handle Write Concern Errors if (result.hasField("writeConcernError")) { BSONObj writeConcernError = result.getObjectField("writeConcernError"); _createWriteConcernError(writeConcernError); } } void WriteResult::_mergeGleResult(const std::vector& ops, const BSONObj& result) { int affected = _getIntOrDefault(result, "n"); // Handle Errors std::string error; if (result.hasField("errmsg")) error = result.getStringField("errmsg"); else if (result.hasField("err")) error = result.getStringField("err"); if (!error.empty()) { // We have errors result.hasField("wtimeout") ? _createWriteConcernError(result) : _createWriteError(result, ops); // Don't update the counts for this gle merge as we have encountered an error return; } // Handle Write Batch switch (ops.front()->operationType()) { case dbWriteInsert: _nInserted += 1; break; case dbWriteDelete: _nRemoved += affected; break; case dbWriteUpdate: if (result.hasField("upserted")) { _createUpsert(result.getField("upserted"), ops); _nUpserted += affected; // DRIVERS-151 -- handle <2.6 servers when upserted _id not returned // // Versions of MongoDB before 2.6 don't return the _id for an upsert // if _id is not an ObjectID. We need to make sure the counts are ok // and extract the _id from the original update operation (the _id in // the update document trumps the one in the query spec if both exist). } else if (result.hasField("updatedExisting") && !result.getBoolField("updatedExisting") && affected == 1) { // Get the update information out of the operation BSONObjBuilder bob; ops.front()->appendSelfToBSONObj(&bob); BSONObj updateOp = bob.obj(); // Extract the _id -- update doc version wins over selector doc BSONElement id = updateOp.getFieldDotted("u._id"); if (id.eoo()) id = updateOp.getFieldDotted("q._id"); _createUpsert(id, ops); _nUpserted += affected; } else { _nMatched += affected; } _setModified(result); break; } } void WriteResult::_check(bool throwSoftErrors) { if (hasWriteErrors()) throw OperationException(writeErrors().back()); if (throwSoftErrors && hasWriteConcernErrors()) { throw OperationException(writeConcernErrors().front()); } } /** * SERVER-13001 - mixed sharded cluster could return nModified * (servers >= 2.6) or not (servers <= 2.4). If any call does * not return nModified we cannot report a valid final count. */ void WriteResult::_setModified(const BSONObj& result) { int nModified = result.getIntField("nModified"); if (_hasModifiedCount && nModified >= 0) _nModified += nModified; else _hasModifiedCount = false; } int WriteResult::_getIntOrDefault(const BSONObj& obj, const StringData& field, const int defaultValue) { return obj.hasField(field) ? obj.getIntField(field) : defaultValue; } int WriteResult::_createUpserts(const BSONElement& upserted, const std::vector& ops) { int nUpserted = 0; BSONObjIterator arrayIterator(upserted.Obj()); while (arrayIterator.more()) { _createUpsert(arrayIterator.next(), ops); nUpserted++; } return nUpserted; } void WriteResult::_createUpsert(const BSONElement& upsert, const std::vector& ops) { int batchIndex = 0; BSONElement id; if (upsert.isABSONObj()) { // Upsert result came from MongoDB 2.6+ batchIndex = _getIntOrDefault(upsert.Obj(), "index"); id = upsert["_id"]; } else { // Upsert result came from MongoDB <2.6 id = upsert; } BSONObjBuilder bob; bob.append("index", static_cast(ops[batchIndex]->getBulkIndex())); bob.appendAs(id, "_id"); _upserted.push_back(bob.obj()); } void WriteResult::_createWriteError(const BSONObj& error, const std::vector& ops) { int batchIndex = _getIntOrDefault(error, "index"); int code = _getIntOrDefault(error, "code", kUnknownError); BSONObjBuilder bob; bob.append("index", static_cast(ops[batchIndex]->getBulkIndex())); bob.append("code", code); bob.append("errmsg", error.getStringField("errmsg")); BSONObjBuilder builder; ops[batchIndex]->appendSelfToBSONObj(&builder); bob.append("op", builder.obj()); if (error.hasField("errInfo")) bob.append("details", error.getObjectField("errInfo")); _writeErrors.push_back(bob.obj()); } void WriteResult::_createWriteConcernError(const BSONObj& error) { BSONObjBuilder bob; int code = _getIntOrDefault(error, "code", kWriteConcernErrorCode); bob.append("code", code); bob.append("errmsg", error.getStringField("errmsg")); if (error.hasField("errInfo")) bob.append("details", error.getObjectField("errInfo")); _writeConcernErrors.push_back(bob.obj()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/client/write_result.h000066400000000000000000000107761273231111400242600ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/client/export_macros.h" #include "mongo/util/net/operation.h" namespace mongo { class BSONObj; class BSONElement; class StringData; class WriteOperation; /** * Class representing the result of a write operations sent to the server. */ class MONGO_CLIENT_API WriteResult { friend class WireProtocolWriter; friend class CommandWriter; friend class BulkOperationBuilder; friend class DBClientBase; public: /** * Creates an empty write result. */ WriteResult(); // // Introspection // /** * Returns true if there have been write errors of any kind. * * This includes write errors and write concern errors. */ bool hasErrors() const; /** * Returns true if there have been write errors. * * These include duplicate key errors, etc... that are possibly encountered in the process * of write execution on the server. */ bool hasWriteErrors() const; /** * Returns true if there have been write concern errors. * * This class of error can occur after the execution of writes on the server if they * cannot be fully persisted or replicated to fulfill given supplied level of write concern. */ bool hasWriteConcernErrors() const; /** * Returns true if the number of modified documents is available. * * This will not be true if any write response comes from a node running MongoDB <2.6. * * Note: You can only call nModified() if hasModifiedCount() is true. */ bool hasModifiedCount() const; // // Data // /** * The number of documents that were inserted. * * Note: This field is always available. */ int nInserted() const; /** * The number of documents that were upserted. * * Note: This field is always available. */ int nUpserted() const; /** * The number of documents that were matched. * * Note: This field is always available. */ int nMatched() const; /** * The number of documents that were modified. * * Warning: This field is only available if hasModifiedCount() is true. */ int nModified() const; /** * The number of documents that were removed. * * Note: This field is always available. */ int nRemoved() const; /** * The information about documents that were upserted. * * Note: The objects in the vector have an "index" and "_id" field. */ const std::vector& upserted() const; // // Errors Data // /** * Vector with the write errors that occurred. */ const std::vector& writeErrors() const; /** * Vector with the write concern errors that occurred. */ const std::vector& writeConcernErrors() const; private: void _mergeWriteConcern(const BSONObj& result); void _mergeCommandResult(const std::vector& ops, const BSONObj& result); void _mergeGleResult(const std::vector& ops, const BSONObj& result); void _check(bool throwSoftErrors); void _setModified(const BSONObj& result); int _getIntOrDefault(const BSONObj& obj, const StringData& field, const int defaultValue = 0); int _createUpserts(const BSONElement& upsert, const std::vector& ops); void _createUpsert(const BSONElement& upsert, const std::vector& ops); void _createWriteError(const BSONObj& error, const std::vector& ops); void _createWriteConcernError(const BSONObj& error); int _nInserted; int _nUpserted; int _nMatched; int _nModified; int _nRemoved; std::vector _upserted; std::vector _writeErrors; std::vector _writeConcernErrors; bool _hasModifiedCount; bool _requiresDetailedInsertResults; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/config.h.in000066400000000000000000000025431273231111400221150ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once // Define to 1 if SSL support is enabled @mongoclient_ssl@ // Define to 1 if SASL support is enabled @mongoclient_sasl@ // Define to 1 if unistd.h is available @mongoclient_have_header_unistd_h@ // Define to 1 if C++11 is available @mongoclient_have_cxx11_atomics@ // Define to 1 if GCC style __atomic functions are available @mongoclient_have_gcc_atomic_builtins@ // Define to 1 if GCC style __sync functions are available @mongoclient_have_gcc_sync_builtins@ // Define to target byte order (1234 vs 4321) @mongoclient_byte_order@ // Define to 1 if std::is_trivially_copyable is supported @mongoclient_have_std_is_trivially_copyable@ // Define to 1 if this platform provides the strnlen(3) function @mongoclient_have_strnlen@ mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/000077500000000000000000000000001273231111400214065ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/crypto.h000066400000000000000000000022141273231111400230760ustar00rootroot00000000000000/** * Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include namespace mongo { namespace crypto { /* * Computes a SHA-1 hash of 'input'. */ bool sha1(const unsigned char* input, const size_t inputLen, unsigned char* output); /* * Computes a HMAC SHA-1 keyed hash of 'input' using the key 'key' */ bool hmacSha1(const unsigned char* key, const size_t keyLen, const unsigned char* input, const size_t inputLen, unsigned char* output, unsigned int* outputLen); } // namespace crypto } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/crypto_openssl.cpp000066400000000000000000000034721273231111400252030ustar00rootroot00000000000000/* * Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/config.h" #ifndef MONGO_SSL #error This file should only be included in SSL-enabled builds #endif #include "mongo/platform/basic.h" #include "mongo/util/scopeguard.h" #include #include #include namespace mongo { namespace crypto { /* * Computes a SHA-1 hash of 'input'. */ bool sha1(const unsigned char* input, const size_t inputLen, unsigned char* output) { EVP_MD_CTX digestCtx; EVP_MD_CTX_init(&digestCtx); ON_BLOCK_EXIT(EVP_MD_CTX_cleanup, &digestCtx); if (1 != EVP_DigestInit_ex(&digestCtx, EVP_sha1(), NULL)) { return false; } if (1 != EVP_DigestUpdate(&digestCtx, input, inputLen)) { return false; } return (1 == EVP_DigestFinal_ex(&digestCtx, output, NULL)); } /* * Computes a HMAC SHA-1 keyed hash of 'input' using the key 'key' */ bool hmacSha1(const unsigned char* key, const size_t keyLen, const unsigned char* input, const size_t inputLen, unsigned char* output, unsigned int* outputLen) { return HMAC(EVP_sha1(), key, keyLen, input, inputLen, output, outputLen); } } // namespace crypto } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/crypto_test.cpp000066400000000000000000000204421273231111400244730ustar00rootroot00000000000000/** * Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/crypto/crypto.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { const int digestLen = 20; // SHA-1 test vectors from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf const struct { const char* msg; unsigned char hash[digestLen]; } sha1Tests[] = {{"abc", {0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d}}, {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", {0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1}}}; TEST(CryptoVectors, SHA1) { unsigned char sha1Result[digestLen]; size_t numTests = sizeof(sha1Tests) / sizeof(sha1Tests[0]); for (size_t i = 0; i < numTests; i++) { ASSERT(crypto::sha1(reinterpret_cast(sha1Tests[i].msg), strlen(sha1Tests[i].msg), sha1Result)) << "Failed SHA1 iteration " << i; ASSERT(0 == memcmp(sha1Tests[i].hash, sha1Result, digestLen)) << "Failed SHA1 iteration " << i; } } const int maxKeySize = 80; const int maxDataSize = 54; // HMAC-SHA-1 test vectors from http://tools.ietf.org/html/rfc2202.html const struct { unsigned char key[maxKeySize]; int keyLen; unsigned char data[maxDataSize]; int dataLen; unsigned char hash[digestLen]; } hmacSha1Tests[] = { // RFC test case 1 {{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 20, {0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65}, 8, {0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00}}, // RFC test case 3 {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 20, {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}, 50, {0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, 0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f, 0x63, 0xf1, 0x75, 0xd3}}, // RFC test case 4 {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}, 25, {0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd}, 50, {0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, 0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c, 0x2d, 0x72, 0x35, 0xda}}, // RFC test case 6 {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80, {0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x46, 0x69, 0x72, 0x73, 0x74}, 54, {0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, 0xed, 0x40, 0x21, 0x12}}}; TEST(CryptoVectors, HMACSHA1) { unsigned char hmacSha1Result[digestLen]; unsigned int hashLen = digestLen; size_t numTests = sizeof(hmacSha1Tests) / sizeof(hmacSha1Tests[0]); for (size_t i = 0; i < numTests; i++) { ASSERT(crypto::hmacSha1(hmacSha1Tests[i].key, hmacSha1Tests[i].keyLen, hmacSha1Tests[i].data, hmacSha1Tests[i].dataLen, hmacSha1Result, &hashLen)) << "Failed HMAC-SHA1 iteration " << i; ASSERT(0 == memcmp(hmacSha1Tests[i].hash, hmacSha1Result, digestLen)) << "Failed HMAC-SHA1 iteration " << i; } } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/mechanism_scram.cpp000066400000000000000000000221251273231111400252450ustar00rootroot00000000000000/* * Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/crypto/mechanism_scram.h" #include #include "mongo/crypto/crypto.h" #include "mongo/platform/random.h" #include "mongo/util/base64.h" namespace mongo { namespace scram { // Compute the SCRAM step Hi() as defined in RFC5802 static void HMACIteration(const unsigned char input[], size_t inputLen, const unsigned char salt[], size_t saltLen, unsigned int iterationCount, unsigned char output[]) { unsigned char intermediateDigest[hashSize]; unsigned char startKey[hashSize]; // Placeholder for HMAC return size, will always be scram::hashSize for HMAC SHA-1 unsigned int hashLen = 0; uassert(17450, "invalid salt length provided", saltLen + 4 == hashSize); memcpy(startKey, salt, saltLen); startKey[saltLen] = 0; startKey[saltLen + 1] = 0; startKey[saltLen + 2] = 0; startKey[saltLen + 3] = 1; // U1 = HMAC(input, salt + 0001) fassert(17494, crypto::hmacSha1(input, inputLen, startKey, saltLen + 4, output, &hashLen)); memcpy(intermediateDigest, output, hashSize); // intermediateDigest contains Ui and output contains the accumulated XOR:ed result for (size_t i = 2; i <= iterationCount; i++) { unsigned char intermediateOutput[hashSize]; fassert(17495, crypto::hmacSha1( input, inputLen, intermediateDigest, hashSize, intermediateOutput, &hashLen)); memcpy(intermediateDigest, intermediateOutput, hashSize); for (size_t k = 0; k < hashSize; k++) { output[k] ^= intermediateDigest[k]; } } } // Iterate the hash function to generate SaltedPassword void generateSaltedPassword(const StringData& hashedPassword, const unsigned char* salt, const int saltLen, const int iterationCount, unsigned char saltedPassword[hashSize]) { // saltedPassword = Hi(hashedPassword, salt) HMACIteration(reinterpret_cast(hashedPassword.rawData()), hashedPassword.size(), salt, saltLen, iterationCount, saltedPassword); } void generateSecrets(const std::string& hashedPassword, const unsigned char salt[], size_t saltLen, size_t iterationCount, unsigned char storedKey[hashSize], unsigned char serverKey[hashSize]) { unsigned char saltedPassword[hashSize]; unsigned char clientKey[hashSize]; unsigned int hashLen = 0; generateSaltedPassword(hashedPassword, salt, saltLen, iterationCount, saltedPassword); // clientKey = HMAC(saltedPassword, "Client Key") fassert(17498, crypto::hmacSha1(saltedPassword, hashSize, reinterpret_cast(clientKeyConst.data()), clientKeyConst.size(), clientKey, &hashLen)); // storedKey = H(clientKey) fassert(17499, crypto::sha1(clientKey, hashSize, storedKey)); // serverKey = HMAC(saltedPassword, "Server Key") fassert(17500, crypto::hmacSha1(saltedPassword, hashSize, reinterpret_cast(serverKeyConst.data()), serverKeyConst.size(), serverKey, &hashLen)); } BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount) { const int saltLenQWords = 2; // Generate salt uint64_t userSalt[saltLenQWords]; boost::scoped_ptr sr(SecureRandom::create()); userSalt[0] = sr->nextInt64(); userSalt[1] = sr->nextInt64(); std::string encodedUserSalt = base64::encode(reinterpret_cast(userSalt), sizeof(userSalt)); // Compute SCRAM secrets serverKey and storedKey unsigned char storedKey[hashSize]; unsigned char serverKey[hashSize]; generateSecrets(hashedPassword, reinterpret_cast(userSalt), saltLenQWords * sizeof(uint64_t), iterationCount, storedKey, serverKey); std::string encodedStoredKey = base64::encode(reinterpret_cast(storedKey), hashSize); std::string encodedServerKey = base64::encode(reinterpret_cast(serverKey), hashSize); return BSON(iterationCountFieldName << iterationCount << saltFieldName << encodedUserSalt << storedKeyFieldName << encodedStoredKey << serverKeyFieldName << encodedServerKey); } std::string generateClientProof(const unsigned char saltedPassword[hashSize], const std::string& authMessage) { // ClientKey := HMAC(saltedPassword, "Client Key") unsigned char clientKey[hashSize]; unsigned int hashLen = 0; fassert(18689, crypto::hmacSha1(saltedPassword, hashSize, reinterpret_cast(clientKeyConst.data()), clientKeyConst.size(), clientKey, &hashLen)); // StoredKey := H(clientKey) unsigned char storedKey[hashSize]; fassert(18701, crypto::sha1(clientKey, hashSize, storedKey)); // ClientSignature := HMAC(StoredKey, AuthMessage) unsigned char clientSignature[hashSize]; fassert(18702, crypto::hmacSha1(storedKey, hashSize, reinterpret_cast(authMessage.c_str()), authMessage.size(), clientSignature, &hashLen)); // ClientProof := ClientKey XOR ClientSignature unsigned char clientProof[hashSize]; for (size_t i = 0; i < hashSize; i++) { clientProof[i] = clientKey[i] ^ clientSignature[i]; } return base64::encode(reinterpret_cast(clientProof), hashSize); } /** * Compare two arrays of bytes for equality in constant time. * * This means that the function runs for the same amount of time even if they differ. Unlike memcmp, * this function does not exit on the first difference. * * Returns true if the two arrays are equal. * * TODO: evaluate if LTO inlines or changes the code flow of this function. */ NOINLINE_DECL bool memequal(volatile const unsigned char* s1, volatile const unsigned char* s2, size_t length) { unsigned char ret = 0; for (size_t i = 0; i < length; ++i) { ret |= s1[i] ^ s2[i]; } return ret == 0; } bool verifyServerSignature(const unsigned char saltedPassword[hashSize], const std::string& authMessage, const std::string& receivedServerSignature) { // ServerKey := HMAC(SaltedPassword, "Server Key") unsigned int hashLen; unsigned char serverKey[hashSize]; fassert(18703, crypto::hmacSha1(saltedPassword, hashSize, reinterpret_cast(serverKeyConst.data()), serverKeyConst.size(), serverKey, &hashLen)); // ServerSignature := HMAC(ServerKey, AuthMessage) unsigned char serverSignature[hashSize]; fassert(18704, crypto::hmacSha1(serverKey, hashSize, reinterpret_cast(authMessage.c_str()), authMessage.size(), serverSignature, &hashLen)); std::string encodedServerSignature = base64::encode(reinterpret_cast(serverSignature), sizeof(serverSignature)); if (encodedServerSignature.size() != receivedServerSignature.size()) { return false; } return memequal(reinterpret_cast(encodedServerSignature.c_str()), reinterpret_cast(receivedServerSignature.c_str()), encodedServerSignature.size()); } } // namespace scram } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/crypto/mechanism_scram.h000066400000000000000000000056741273231111400247240ustar00rootroot00000000000000/* Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/status.h" #include "mongo/db/jsobj.h" namespace mongo { namespace scram { const unsigned int hashSize = 20; const std::string serverKeyConst = "Server Key"; const std::string clientKeyConst = "Client Key"; const std::string iterationCountFieldName = "iterationCount"; const std::string saltFieldName = "salt"; const std::string storedKeyFieldName = "storedKey"; const std::string serverKeyFieldName = "serverKey"; /* * Computes the SaltedPassword from password, salt and iterationCount. */ void generateSaltedPassword(const StringData& hashedPassword, const unsigned char* salt, const int saltLen, const int iterationCount, unsigned char saltedPassword[hashSize]); /* * Computes the SCRAM secrets storedKey and serverKey using the salt 'salt' * and iteration count 'iterationCount' as defined in RFC5802 (server side). */ void generateSecrets(const std::string& hashedPassword, const unsigned char salt[], size_t saltLen, size_t iterationCount, unsigned char storedKey[hashSize], unsigned char serverKey[hashSize]); /* * Generates the user salt and the SCRAM secrets storedKey and serverKey as * defined in RFC5802 (server side). */ BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount); /* * Computes the ClientProof from SaltedPassword and authMessage (client side). */ std::string generateClientProof(const unsigned char saltedPassword[hashSize], const std::string& authMessage); /* * Validates that the provided password 'hashedPassword' generates the serverKey * 'serverKey' given iteration count 'iterationCount' and salt 'salt'. */ bool validatePassword(const std::string& hashedPassword, int iterationCount, const std::string& salt, const std::string& storedKey); /* * Verifies ServerSignature (client side). */ bool verifyServerSignature(const unsigned char saltedPassword[hashSize], const std::string& authMessage, const std::string& serverSignature); } // namespace scram } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/db/000077500000000000000000000000001273231111400204535ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/db/dbmessage.cpp000066400000000000000000000147531273231111400231230ustar00rootroot00000000000000// dbmessage.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/db/dbmessage.h" #include "mongo/client/options.h" #include "mongo/client/private/options.h" #include "mongo/platform/strnlen.h" namespace mongo { using std::string; using std::stringstream; string Message::toString() const { stringstream ss; ss << "op: " << opToString(operation()) << " len: " << size(); if (operation() >= 2000 && operation() < 2100) { DbMessage d(*this); ss << " ns: " << d.getns(); switch (operation()) { case dbUpdate: { int flags = d.pullInt(); BSONObj q = d.nextJsObj(); BSONObj o = d.nextJsObj(); ss << " flags: " << flags << " query: " << q << " update: " << o; break; } case dbInsert: ss << d.nextJsObj(); break; case dbDelete: { int flags = d.pullInt(); BSONObj q = d.nextJsObj(); ss << " flags: " << flags << " query: " << q; break; } default: ss << " CANNOT HANDLE YET"; } } return ss.str(); } DbMessage::DbMessage(const Message& msg) : _msg(msg), _nsStart(NULL), _mark(NULL), _nsLen(0) { // for received messages, Message has only one buffer _theEnd = _msg.singleData().data() + _msg.singleData().dataLen(); _nextjsobj = _msg.singleData().data(); _reserved = readAndAdvance(); // Read packet for NS if (messageShouldHaveNs()) { // Limit = buffer size of message - // (first int4 in message which is either flags or a zero constant) size_t limit = _msg.singleData().dataLen() - sizeof(int); _nsStart = _nextjsobj; _nsLen = strnlen(_nsStart, limit); // Validate there is room for a null byte in the buffer // Strings can be zero length uassert(18633, "Failed to parse ns string", _nsLen < limit); _nextjsobj += _nsLen + 1; // skip namespace + null } } const char* DbMessage::getns() const { verify(messageShouldHaveNs()); return _nsStart; } int DbMessage::getQueryNToReturn() const { verify(messageShouldHaveNs()); const char* p = _nsStart + _nsLen + 1; checkRead(p, 2); return ConstDataView(p).readLE(sizeof(int32_t)); } int DbMessage::pullInt() { return readAndAdvance(); } long long DbMessage::pullInt64() { return readAndAdvance(); } const char* DbMessage::getArray(size_t count) const { checkRead(_nextjsobj, count); return _nextjsobj; } BSONObj DbMessage::nextJsObj() { massert(10304, "Client Error: Remaining data too small for BSON object", _nextjsobj != NULL && _theEnd - _nextjsobj >= 5); if (client::Options::current().validateObjects()) { Status status = validateBSON(_nextjsobj, _theEnd - _nextjsobj); massert(10307, str::stream() << "Client Error: bad object in message: " << status.reason(), status.isOK()); } BSONObj js(_nextjsobj); verify(js.objsize() >= 5); verify(js.objsize() <= (_theEnd - _nextjsobj)); _nextjsobj += js.objsize(); if (_nextjsobj >= _theEnd) _nextjsobj = NULL; return js; } void DbMessage::markReset(const char* toMark = NULL) { if (toMark == NULL) { toMark = _mark; } verify(toMark); _nextjsobj = toMark; } template void DbMessage::checkRead(const char* start, size_t count) const { if ((_theEnd - start) < static_cast(sizeof(T) * count)) { uassert(18634, "Not enough data to read", false); } } template T DbMessage::read() const { checkRead(_nextjsobj, 1); return ConstDataView(_nextjsobj).readLE(); } template T DbMessage::readAndAdvance() { T t = read(); _nextjsobj += sizeof(T); return t; } void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, void* data, int size, int nReturned, int startingFrom, long long cursorId) { BufBuilder b(32768); b.skip(sizeof(QueryResult::Value)); b.appendBuf(data, size); QueryResult::View qr = b.buf(); qr.setResultFlags(queryResultFlags); qr.msgdata().setLen(b.len()); qr.msgdata().setOperation(opReply); qr.setCursorId(cursorId); qr.setStartingFrom(startingFrom); qr.setNReturned(nReturned); b.decouple(); Message resp(qr.view2ptr(), true); p->reply(requestMsg, resp, requestMsg.header().getId()); } void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, const BSONObj& responseObj) { replyToQuery( queryResultFlags, p, requestMsg, (void*)responseObj.objdata(), responseObj.objsize(), 1); } void replyToQuery(int queryResultFlags, Message& m, DbResponse& dbresponse, BSONObj obj) { Message* resp = new Message(); replyToQuery(queryResultFlags, *resp, obj); dbresponse.response = resp; dbresponse.responseTo = m.header().getId(); } void replyToQuery(int queryResultFlags, Message& response, const BSONObj& resultObj) { BufBuilder bufBuilder; bufBuilder.skip(sizeof(QueryResult::Value)); bufBuilder.appendBuf(reinterpret_cast(const_cast(resultObj.objdata())), resultObj.objsize()); QueryResult::View queryResult = bufBuilder.buf(); bufBuilder.decouple(); queryResult.setResultFlags(queryResultFlags); queryResult.msgdata().setLen(bufBuilder.len()); queryResult.msgdata().setOperation(opReply); queryResult.setCursorId(0); queryResult.setStartingFrom(0); queryResult.setNReturned(1); response.setData(queryResult.view2ptr(), true); // transport will free } } mongo-cxx-driver-legacy-1.1.2/src/mongo/db/dbmessage.h000066400000000000000000000214161273231111400225620ustar00rootroot00000000000000// dbmessage.h /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/bson/bson_validate.h" #include "mongo/client/constants.h" #include "mongo/db/jsobj.h" #include "mongo/util/net/message.h" #include "mongo/util/net/message_port.h" namespace mongo { /* db response format Query or GetMore: // see struct QueryResult int resultFlags; int64 cursorID; int startingFrom; int nReturned; list of marshalled JSObjects; */ /* db request message format unsigned opid; // arbitary; will be echoed back byte operation; int options; then for: dbInsert: string collection; a series of JSObjects dbDelete: string collection; int flags=0; // 1=DeleteSingle JSObject query; dbUpdate: string collection; int flags; // 1=upsert JSObject query; JSObject objectToUpdate; objectToUpdate may include { $inc: } or { $set: ... }, see struct Mod. dbQuery: string collection; int nToSkip; int nToReturn; // how many you want back as the beginning of the cursor data (0=no limit) // greater than zero is simply a hint on how many objects to send back per // "cursor batch". a negative number indicates a hard limit. JSObject query; [JSObject fieldsToReturn] dbGetMore: string collection; // redundant, might use for security. int nToReturn; int64 cursorID; dbKillCursors=2007: int n; int64 cursorIDs[n]; Note that on Update, there is only one object, which is different from insert where you can pass a list of objects to insert in the db. Note that the update field layout is very similar layout to Query. */ namespace QueryResult { #pragma pack(1) /* see http://dochub.mongodb.org/core/mongowireprotocol */ struct Layout { MsgData::Layout msgdata; int64_t cursorId; int32_t startingFrom; int32_t nReturned; }; #pragma pack() class ConstView { public: ConstView(const char* storage) : _storage(storage) {} const char* view2ptr() const { return storage().view(); } MsgData::ConstView msgdata() const { return storage().view(offsetof(Layout, msgdata)); } int64_t getCursorId() const { return storage().readLE(offsetof(Layout, cursorId)); } int32_t getStartingFrom() const { return storage().readLE(offsetof(Layout, startingFrom)); } int32_t getNReturned() const { return storage().readLE(offsetof(Layout, nReturned)); } const char* data() const { return storage().view(sizeof(Layout)); } protected: const ConstDataView& storage() const { return _storage; } private: ConstDataView _storage; }; class View : public ConstView { public: View(char* data) : ConstView(data) {} using ConstView::view2ptr; char* view2ptr() { return storage().view(); } using ConstView::msgdata; MsgData::View msgdata() { return storage().view(offsetof(Layout, msgdata)); } void setCursorId(int64_t value) { storage().writeLE(value, offsetof(Layout, cursorId)); } void setStartingFrom(int32_t value) { storage().writeLE(value, offsetof(Layout, startingFrom)); } void setNReturned(int32_t value) { storage().writeLE(value, offsetof(Layout, nReturned)); } int32_t getResultFlags() { return DataView(msgdata().data()).readLE(); } void setResultFlags(int32_t value) { DataView(msgdata().data()).writeLE(value); } void setResultFlagsToOk() { setResultFlags(ResultFlag_AwaitCapable); } void initializeResultFlags() { setResultFlags(0); } private: DataView storage() const { return const_cast(ConstView::view2ptr()); } }; class Value : public EncodedValueStorage { public: Value() { BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout)); } Value(ZeroInitTag_t zit) : EncodedValueStorage(zit) {} }; } // namespace QueryResult /* For the database/server protocol, these objects and functions encapsulate the various messages transmitted over the connection. See http://dochub.mongodb.org/core/mongowireprotocol */ class DbMessage { // Assume sizeof(int) == 4 bytes BOOST_STATIC_ASSERT(sizeof(int) == 4); public: // Note: DbMessage constructor reads the first 4 bytes and stores it in reserved DbMessage(const Message& msg); // Indicates whether this message is expected to have a ns // or in the case of dbMsg, a string in the same place as ns bool messageShouldHaveNs() const { return (_msg.operation() >= dbMsg) & (_msg.operation() <= dbDelete); } /** the 32 bit field before the ns * track all bit usage here as its cross op * 0: InsertOption_ContinueOnError * 1: fromWriteback */ int reservedField() const { return _reserved; } const char* getns() const; int getQueryNToReturn() const; int pullInt(); long long pullInt64(); const char* getArray(size_t count) const; /* for insert and update msgs */ bool moreJSObjs() const { return _nextjsobj != 0; } BSONObj nextJsObj(); const Message& msg() const { return _msg; } const char* markGet() const { return _nextjsobj; } void markSet() { _mark = _nextjsobj; } void markReset(const char* toMark); private: // Check if we have enough data to read template void checkRead(const char* start, size_t count = 0) const; // Read some type without advancing our position template T read() const; // Read some type, and advance our position template T readAndAdvance(); const Message& _msg; int _reserved; // flags or zero depending on packet, starts the packet const char* _nsStart; // start of namespace string, +4 from message start const char* _nextjsobj; // current position reading packet const char* _theEnd; // end of packet const char* _mark; unsigned int _nsLen; }; /* a request to run a query, received from the database */ class QueryMessage { public: const char* ns; int ntoskip; int ntoreturn; int queryOptions; BSONObj query; BSONObj fields; /** * parses the message into the above fields * Warning: constructor mutates DbMessage. */ QueryMessage(DbMessage& d) { ns = d.getns(); ntoskip = d.pullInt(); ntoreturn = d.pullInt(); query = d.nextJsObj(); if (d.moreJSObjs()) { fields = d.nextJsObj(); } queryOptions = DataView(d.msg().header().data()).readLE(); } }; /** * A response to a DbMessage. */ struct DbResponse { Message* response; MSGID responseTo; std::string exhaustNS; /* points to ns if exhaust mode. 0=normal mode*/ DbResponse(Message* r, MSGID rt) : response(r), responseTo(rt) {} DbResponse() { response = 0; } ~DbResponse() { delete response; } }; void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, void* data, int size, int nReturned, int startingFrom = 0, long long cursorId = 0); /* object reply helper. */ void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, const BSONObj& responseObj); /* helper to do a reply using a DbResponse object */ void replyToQuery(int queryResultFlags, Message& m, DbResponse& dbresponse, BSONObj obj); /** * Helper method for setting up a response object. * * @param queryResultFlags The flags to set to the response object. * @param response The object to be used for building the response. The internal buffer of * this object will contain the raw data from resultObj after a successful call. * @param resultObj The bson object that contains the reply data. */ void replyToQuery(int queryResultFlags, Message& response, const BSONObj& resultObj); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/db/dbmessage_test.cpp000066400000000000000000000062271273231111400241570ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include "mongo/bson/util/builder.h" #include "mongo/db/dbmessage.h" #include "mongo/unittest/unittest.h" namespace mongo { using std::string; // Test if the reserved field is short of 4 bytes TEST(DBMessage1, ShortFlags) { BufBuilder b; string ns("test"); b.appendChar(1); Message toSend; toSend.setData(dbDelete, b.buf(), b.len()); ASSERT_THROWS(DbMessage d1(toSend), UserException); } // Test a short NS missing a trailing null TEST(DBMessage1, BadNS) { BufBuilder b; b.appendNum(static_cast(1)); b.appendChar('b'); b.appendChar('a'); b.appendChar('d'); // Forget to append \0 Message toSend; toSend.setData(dbDelete, b.buf(), b.len()); ASSERT_THROWS(DbMessage d1(toSend), UserException); } // Test a valid kill message and try an extra pull TEST(DBMessage1, GoodKill) { BufBuilder b; b.appendNum(static_cast(1)); b.appendNum(static_cast(3)); Message toSend; toSend.setData(dbKillCursors, b.buf(), b.len()); DbMessage d1(toSend); ASSERT_EQUALS(3, d1.pullInt()); ASSERT_THROWS(d1.pullInt(), UserException); } // Try a bad read of a type too large TEST(DBMessage1, GoodKill2) { BufBuilder b; b.appendNum(static_cast(1)); b.appendNum(static_cast(3)); Message toSend; toSend.setData(dbKillCursors, b.buf(), b.len()); DbMessage d1(toSend); ASSERT_THROWS(d1.pullInt64(), UserException); } // Test a basic good insert, and an extra read TEST(DBMessage1, GoodInsert) { BufBuilder b; string ns("test"); b.appendNum(static_cast(1)); b.appendStr(ns); b.appendNum(static_cast(3)); b.appendNum(static_cast(39)); Message toSend; toSend.setData(dbInsert, b.buf(), b.len()); DbMessage d1(toSend); ASSERT_EQUALS(3, d1.pullInt()); ASSERT_EQUALS(39, d1.pullInt()); ASSERT_THROWS(d1.pullInt(), UserException); } // Test a basic good insert, and an extra read TEST(DBMessage1, GoodInsert2) { BufBuilder b; string ns("test"); b.appendNum(static_cast(1)); b.appendStr(ns); b.appendNum(static_cast(3)); b.appendNum(static_cast(39)); BSONObj bo = BSON("ts" << 0); bo.appendSelfToBufBuilder(b); Message toSend; toSend.setData(dbInsert, b.buf(), b.len()); DbMessage d1(toSend); ASSERT_EQUALS(3, d1.pullInt()); ASSERT_EQUALS(39, d1.pullInt()); BSONObj bo2 = d1.nextJsObj(); ASSERT_THROWS(d1.nextJsObj(), MsgAssertionException); } } // mongo namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/db/jsobj.h000066400000000000000000000025171273231111400217400ustar00rootroot00000000000000/** @file jsobj.h BSON classes */ /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** BSONObj and its helpers "BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be represented in JSON (plus a few extensions useful for databases & other languages). http://www.bsonspec.org/ */ #pragma once #include "mongo/bson/util/builder.h" #include "mongo/bson/bsontypes.h" #include "mongo/bson/oid.h" #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/bsonobjiterator.h" #include "mongo/bson/bson-inl.h" #include "mongo/bson/ordering.h" #include "mongo/base/string_data.h" #include "mongo/bson/bson_db.h" #include "mongo/bson/timestamp.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/db/json.cpp000066400000000000000000001203741273231111400221370ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/db/json.h" #include #include #include "mongo/base/parse_number.h" #include "mongo/db/jsobj.h" #include "mongo/platform/cstdint.h" #include "mongo/platform/strtoll.h" #include "mongo/util/base64.h" #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/time_support.h" namespace mongo { using std::ostringstream; using std::string; using boost::scoped_ptr; #if 0 #define MONGO_JSON_DEBUG(message) \ log() << "JSON DEBUG @ " << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << ": " \ << message << endl; #else #define MONGO_JSON_DEBUG(message) #endif #define ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" #define DIGIT "0123456789" #define CONTROL "\a\b\f\n\r\t\v" #define JOPTIONS "gims" // Size hints given to char vectors enum { ID_RESERVE_SIZE = 64, PAT_RESERVE_SIZE = 4096, OPT_RESERVE_SIZE = 64, FIELD_RESERVE_SIZE = 4096, STRINGVAL_RESERVE_SIZE = 4096, BINDATA_RESERVE_SIZE = 4096, BINDATATYPE_RESERVE_SIZE = 4096, NS_RESERVE_SIZE = 64, DB_RESERVE_SIZE = 64, NUMBERLONG_RESERVE_SIZE = 64, DATE_RESERVE_SIZE = 64 }; static const char* LBRACE = "{", * RBRACE = "}", * LBRACKET = "[", * RBRACKET = "]", * LPAREN = "(", * RPAREN = ")", * COLON = ":", * COMMA = ",", * FORWARDSLASH = "/", * SINGLEQUOTE = "'", * DOUBLEQUOTE = "\""; JParse::JParse(const StringData& str) : _buf(str.rawData()), _input(_buf), _input_end(_input + str.size()) {} Status JParse::parseError(const StringData& msg) { std::ostringstream ossmsg; ossmsg << msg; ossmsg << ": offset:"; ossmsg << offset(); ossmsg << " of:"; ossmsg << _buf; return Status(ErrorCodes::FailedToParse, ossmsg.str()); } Status JParse::value(const StringData& fieldName, BSONObjBuilder& builder) { MONGO_JSON_DEBUG("fieldName: " << fieldName); if (peekToken(LBRACE)) { Status ret = object(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (peekToken(LBRACKET)) { Status ret = array(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("new")) { Status ret = constructor(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("Date")) { Status ret = date(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("Timestamp")) { Status ret = timestamp(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("ObjectId")) { Status ret = objectId(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("NumberLong")) { Status ret = numberLong(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("NumberInt")) { Status ret = numberInt(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (readToken("Dbref") || readToken("DBRef")) { Status ret = dbRef(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (peekToken(FORWARDSLASH)) { Status ret = regex(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (peekToken(DOUBLEQUOTE) || peekToken(SINGLEQUOTE)) { std::string valueString; valueString.reserve(STRINGVAL_RESERVE_SIZE); Status ret = quotedString(&valueString); if (ret != Status::OK()) { return ret; } builder.append(fieldName, valueString); } else if (readToken("true")) { builder.append(fieldName, true); } else if (readToken("false")) { builder.append(fieldName, false); } else if (readToken("null")) { builder.appendNull(fieldName); } else if (readToken("undefined")) { builder.appendUndefined(fieldName); } else if (readToken("NaN")) { builder.append(fieldName, std::numeric_limits::quiet_NaN()); } else if (readToken("Infinity")) { builder.append(fieldName, std::numeric_limits::infinity()); } else if (readToken("-Infinity")) { builder.append(fieldName, -std::numeric_limits::infinity()); } else { Status ret = number(fieldName, builder); if (ret != Status::OK()) { return ret; } } return Status::OK(); } Status JParse::parse(BSONObjBuilder& builder) { return isArray() ? array("UNUSED", builder, false) : object("UNUSED", builder, false); } Status JParse::object(const StringData& fieldName, BSONObjBuilder& builder, bool subObject) { MONGO_JSON_DEBUG("fieldName: " << fieldName); if (!readToken(LBRACE)) { return parseError("Expecting '{'"); } // Empty object if (readToken(RBRACE)) { if (subObject) { BSONObjBuilder empty(builder.subobjStart(fieldName)); empty.done(); } return Status::OK(); } // Special object std::string firstField; firstField.reserve(FIELD_RESERVE_SIZE); Status ret = field(&firstField); if (ret != Status::OK()) { return ret; } if (firstField == "$oid") { if (!subObject) { return parseError("Reserved field name in base object: $oid"); } Status ret = objectIdObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$binary") { if (!subObject) { return parseError("Reserved field name in base object: $binary"); } Status ret = binaryObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$date") { if (!subObject) { return parseError("Reserved field name in base object: $date"); } Status ret = dateObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$timestamp") { if (!subObject) { return parseError("Reserved field name in base object: $timestamp"); } Status ret = timestampObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$regex") { if (!subObject) { return parseError("Reserved field name in base object: $regex"); } Status ret = regexObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$ref") { if (!subObject) { return parseError("Reserved field name in base object: $ref"); } Status ret = dbRefObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$undefined") { if (!subObject) { return parseError("Reserved field name in base object: $undefined"); } Status ret = undefinedObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$numberLong") { if (!subObject) { return parseError("Reserved field name in base object: $numberLong"); } Status ret = numberLongObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$minKey") { if (!subObject) { return parseError("Reserved field name in base object: $minKey"); } Status ret = minKeyObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else if (firstField == "$maxKey") { if (!subObject) { return parseError("Reserved field name in base object: $maxKey"); } Status ret = maxKeyObject(fieldName, builder); if (ret != Status::OK()) { return ret; } } else { // firstField != // Normal object // Only create a sub builder if this is not the base object BSONObjBuilder* objBuilder = &builder; scoped_ptr subObjBuilder; if (subObject) { subObjBuilder.reset(new BSONObjBuilder(builder.subobjStart(fieldName))); objBuilder = subObjBuilder.get(); } if (!readToken(COLON)) { return parseError("Expecting ':'"); } Status valueRet = value(firstField, *objBuilder); if (valueRet != Status::OK()) { return valueRet; } while (readToken(COMMA)) { std::string fieldName; fieldName.reserve(FIELD_RESERVE_SIZE); Status fieldRet = field(&fieldName); if (fieldRet != Status::OK()) { return fieldRet; } if (!readToken(COLON)) { return parseError("Expecting ':'"); } Status valueRet = value(fieldName, *objBuilder); if (valueRet != Status::OK()) { return valueRet; } } } if (!readToken(RBRACE)) { return parseError("Expecting '}' or ','"); } return Status::OK(); } Status JParse::objectIdObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expected ':'"); } std::string id; id.reserve(ID_RESERVE_SIZE); Status ret = quotedString(&id); if (ret != Status::OK()) { return ret; } if (id.size() != 24) { return parseError("Expecting 24 hex digits: " + id); } if (!isHexString(id)) { return parseError("Expecting hex digits: " + id); } builder.append(fieldName, OID(id)); return Status::OK(); } Status JParse::binaryObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expected ':'"); } std::string binDataString; binDataString.reserve(BINDATA_RESERVE_SIZE); Status dataRet = quotedString(&binDataString); if (dataRet != Status::OK()) { return dataRet; } if (binDataString.size() % 4 != 0) { return parseError("Invalid length base64 encoded string"); } if (!isBase64String(binDataString)) { return parseError("Invalid character in base64 encoded string"); } const std::string& binData = base64::decode(binDataString); if (!readToken(COMMA)) { return parseError("Expected ','"); } if (!readField("$type")) { return parseError("Expected second field name: \"$type\", in \"$binary\" object"); } if (!readToken(COLON)) { return parseError("Expected ':'"); } std::string binDataType; binDataType.reserve(BINDATATYPE_RESERVE_SIZE); Status typeRet = quotedString(&binDataType); if (typeRet != Status::OK()) { return typeRet; } if ((binDataType.size() != 2) || !isHexString(binDataType)) { return parseError( "Argument of $type in $bindata object must be a hex string representation of a single " "byte"); } builder.appendBinData( fieldName, binData.length(), BinDataType(fromHex(binDataType)), binData.data()); return Status::OK(); } Status JParse::dateObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expected ':'"); } errno = 0; char* endptr; Date_t date; if (peekToken(DOUBLEQUOTE)) { std::string dateString; dateString.reserve(DATE_RESERVE_SIZE); Status ret = quotedString(&dateString); if (!ret.isOK()) { return ret; } StatusWith dateRet = dateFromISOString(dateString); if (!dateRet.isOK()) { return dateRet.getStatus(); } date = dateRet.getValue(); } else if (readToken(LBRACE)) { std::string fieldName; fieldName.reserve(FIELD_RESERVE_SIZE); Status ret = field(&fieldName); if (ret != Status::OK()) { return ret; } if (fieldName != "$numberLong") { return parseError("Expected field name: $numberLong for $date value object"); } if (!readToken(COLON)) { return parseError("Expecting ':'"); } // The number must be a quoted string, since large long numbers could overflow a double // and thus may not be valid JSON std::string numberLongString; numberLongString.reserve(NUMBERLONG_RESERVE_SIZE); ret = quotedString(&numberLongString); if (!ret.isOK()) { return ret; } long long numberLong; ret = parseNumberFromString(numberLongString, &numberLong); if (!ret.isOK()) { return ret; } date = numberLong; } else { // SERVER-11920: We should use parseNumberFromString here, but that function requires // that we know ahead of time where the number ends, which is not currently the case. date = static_cast(strtoll(_input, &endptr, 10)); if (_input == endptr) { return parseError("Date expecting integer milliseconds"); } if (errno == ERANGE) { /* Need to handle this because jsonString outputs the value of Date_t as unsigned. * See SERVER-8330 and SERVER-8573 */ errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function // requires that we know ahead of time where the number ends, which is not currently // the case. date = strtoull(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Date milliseconds overflow"); } } _input = endptr; } builder.appendDate(fieldName, date); return Status::OK(); } Status JParse::timestampObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (!readToken(LBRACE)) { return parseError("Expecting '{' to start \"$timestamp\" object"); } if (!readField("t")) { return parseError("Expected field name \"t\" in \"$timestamp\" sub object"); } if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (readToken("-")) { return parseError("Negative seconds in \"$timestamp\""); } errno = 0; char* endptr; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. uint32_t seconds = strtoul(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Timestamp seconds overflow"); } if (_input == endptr) { return parseError("Expecting unsigned integer seconds in \"$timestamp\""); } _input = endptr; if (!readToken(COMMA)) { return parseError("Expecting ','"); } if (!readField("i")) { return parseError("Expected field name \"i\" in \"$timestamp\" sub object"); } if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (readToken("-")) { return parseError("Negative increment in \"$timestamp\""); } errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. uint32_t count = strtoul(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Timestamp increment overflow"); } if (_input == endptr) { return parseError("Expecting unsigned integer increment in \"$timestamp\""); } _input = endptr; if (!readToken(RBRACE)) { return parseError("Expecting '}'"); } builder.appendTimestamp(fieldName, Timestamp_t(seconds, count)); return Status::OK(); } Status JParse::regexObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } std::string pat; pat.reserve(PAT_RESERVE_SIZE); Status patRet = quotedString(&pat); if (patRet != Status::OK()) { return patRet; } if (readToken(COMMA)) { if (!readField("$options")) { return parseError("Expected field name: \"$options\" in \"$regex\" object"); } if (!readToken(COLON)) { return parseError("Expecting ':'"); } std::string opt; opt.reserve(OPT_RESERVE_SIZE); Status optRet = quotedString(&opt); if (optRet != Status::OK()) { return optRet; } Status optCheckRet = regexOptCheck(opt); if (optCheckRet != Status::OK()) { return optCheckRet; } builder.appendRegex(fieldName, pat, opt); } else { builder.appendRegex(fieldName, pat, ""); } return Status::OK(); } Status JParse::dbRefObject(const StringData& fieldName, BSONObjBuilder& builder) { BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); if (!readToken(COLON)) { return parseError("DBRef: Expecting ':'"); } std::string ns; ns.reserve(NS_RESERVE_SIZE); Status ret = quotedString(&ns); if (ret != Status::OK()) { return ret; } subBuilder.append("$ref", ns); if (!readToken(COMMA)) { return parseError("DBRef: Expecting ','"); } if (!readField("$id")) { return parseError("DBRef: Expected field name: \"$id\" in \"$ref\" object"); } if (!readToken(COLON)) { return parseError("DBRef: Expecting ':'"); } Status valueRet = value("$id", subBuilder); if (valueRet != Status::OK()) { return valueRet; } if (readToken(COMMA)) { if (!readField("$db")) { return parseError("DBRef: Expected field name: \"$db\" in \"$ref\" object"); } if (!readToken(COLON)) { return parseError("DBRef: Expecting ':'"); } std::string db; db.reserve(DB_RESERVE_SIZE); ret = quotedString(&db); if (ret != Status::OK()) { return ret; } subBuilder.append("$db", db); } subBuilder.done(); return Status::OK(); } Status JParse::undefinedObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (!readToken("true")) { return parseError("Reserved field \"$undefined\" requires value of true"); } builder.appendUndefined(fieldName); return Status::OK(); } Status JParse::numberLongObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } // The number must be a quoted string, since large long numbers could overflow a double and // thus may not be valid JSON std::string numberLongString; numberLongString.reserve(NUMBERLONG_RESERVE_SIZE); Status ret = quotedString(&numberLongString); if (!ret.isOK()) { return ret; } long long numberLong; ret = parseNumberFromString(numberLongString, &numberLong); if (!ret.isOK()) { return ret; } builder.appendNumber(fieldName, numberLong); return Status::OK(); } Status JParse::minKeyObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (!readToken("1")) { return parseError("Reserved field \"$minKey\" requires value of 1"); } builder.appendMinKey(fieldName); return Status::OK(); } Status JParse::maxKeyObject(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(COLON)) { return parseError("Expecting ':'"); } if (!readToken("1")) { return parseError("Reserved field \"$maxKey\" requires value of 1"); } builder.appendMaxKey(fieldName); return Status::OK(); } Status JParse::array(const StringData& fieldName, BSONObjBuilder& builder, bool subObject) { MONGO_JSON_DEBUG("fieldName: " << fieldName); uint32_t index(0); if (!readToken(LBRACKET)) { return parseError("Expecting '['"); } BSONObjBuilder* arrayBuilder = &builder; scoped_ptr subObjBuilder; if (subObject) { subObjBuilder.reset(new BSONObjBuilder(builder.subarrayStart(fieldName))); arrayBuilder = subObjBuilder.get(); } if (!peekToken(RBRACKET)) { do { Status ret = value(builder.numStr(index), *arrayBuilder); if (ret != Status::OK()) { return ret; } index++; } while (readToken(COMMA)); } arrayBuilder->done(); if (!readToken(RBRACKET)) { return parseError("Expecting ']' or ','"); } return Status::OK(); } /* NOTE: this could be easily modified to allow "new" before other * constructors, but for now it only allows "new" before Date(). * Also note that unlike the interactive shell "Date(x)" and "new Date(x)" * have the same behavior. XXX: this may not be desired. */ Status JParse::constructor(const StringData& fieldName, BSONObjBuilder& builder) { if (readToken("Date")) { date(fieldName, builder); } else { return parseError("\"new\" keyword not followed by Date constructor"); } return Status::OK(); } Status JParse::date(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(LPAREN)) { return parseError("Expecting '('"); } errno = 0; char* endptr; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. Date_t date = static_cast(strtoll(_input, &endptr, 10)); if (_input == endptr) { return parseError("Date expecting integer milliseconds"); } if (errno == ERANGE) { /* Need to handle this because jsonString outputs the value of Date_t as unsigned. * See SERVER-8330 and SERVER-8573 */ errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function requires // that we know ahead of time where the number ends, which is not currently the case. date = strtoull(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Date milliseconds overflow"); } } _input = endptr; if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } builder.appendDate(fieldName, date); return Status::OK(); } Status JParse::timestamp(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(LPAREN)) { return parseError("Expecting '('"); } if (readToken("-")) { return parseError("Negative seconds in \"$timestamp\""); } errno = 0; char* endptr; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. uint32_t seconds = strtoul(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Timestamp seconds overflow"); } if (_input == endptr) { return parseError("Expecting unsigned integer seconds in \"$timestamp\""); } _input = endptr; if (!readToken(COMMA)) { return parseError("Expecting ','"); } if (readToken("-")) { return parseError("Negative seconds in \"$timestamp\""); } errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. uint32_t count = strtoul(_input, &endptr, 10); if (errno == ERANGE) { return parseError("Timestamp increment overflow"); } if (_input == endptr) { return parseError("Expecting unsigned integer increment in \"$timestamp\""); } _input = endptr; if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } builder.appendTimestamp(fieldName, Timestamp_t(seconds, count)); return Status::OK(); } Status JParse::objectId(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(LPAREN)) { return parseError("Expecting '('"); } std::string id; id.reserve(ID_RESERVE_SIZE); Status ret = quotedString(&id); if (ret != Status::OK()) { return ret; } if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } if (id.size() != 24) { return parseError("Expecting 24 hex digits: " + id); } if (!isHexString(id)) { return parseError("Expecting hex digits: " + id); } builder.append(fieldName, OID(id)); return Status::OK(); } Status JParse::numberLong(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(LPAREN)) { return parseError("Expecting '('"); } errno = 0; char* endptr; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. int64_t val = strtoll(_input, &endptr, 10); if (errno == ERANGE) { return parseError("NumberLong out of range"); } if (_input == endptr) { return parseError("Expecting number in NumberLong"); } _input = endptr; if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } builder.appendNumber(fieldName, static_cast(val)); return Status::OK(); } Status JParse::numberInt(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(LPAREN)) { return parseError("Expecting '('"); } errno = 0; char* endptr; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. int32_t val = strtol(_input, &endptr, 10); if (errno == ERANGE) { return parseError("NumberInt out of range"); } if (_input == endptr) { return parseError("Expecting unsigned number in NumberInt"); } _input = endptr; if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } builder.appendNumber(fieldName, static_cast(val)); return Status::OK(); } Status JParse::dbRef(const StringData& fieldName, BSONObjBuilder& builder) { BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); if (!readToken(LPAREN)) { return parseError("Expecting '('"); } std::string ns; ns.reserve(NS_RESERVE_SIZE); Status refRet = quotedString(&ns); if (refRet != Status::OK()) { return refRet; } subBuilder.append("$ref", ns); if (!readToken(COMMA)) { return parseError("Expecting ','"); } Status valueRet = value("$id", subBuilder); if (valueRet != Status::OK()) { return valueRet; } if (readToken(COMMA)) { std::string db; db.reserve(DB_RESERVE_SIZE); Status dbRet = quotedString(&db); if (dbRet != Status::OK()) { return dbRet; } subBuilder.append("$db", db); } if (!readToken(RPAREN)) { return parseError("Expecting ')'"); } subBuilder.done(); return Status::OK(); } Status JParse::regex(const StringData& fieldName, BSONObjBuilder& builder) { if (!readToken(FORWARDSLASH)) { return parseError("Expecting '/'"); } std::string pat; pat.reserve(PAT_RESERVE_SIZE); Status patRet = regexPat(&pat); if (patRet != Status::OK()) { return patRet; } if (!readToken(FORWARDSLASH)) { return parseError("Expecting '/'"); } std::string opt; opt.reserve(OPT_RESERVE_SIZE); Status optRet = regexOpt(&opt); if (optRet != Status::OK()) { return optRet; } Status optCheckRet = regexOptCheck(opt); if (optCheckRet != Status::OK()) { return optCheckRet; } builder.appendRegex(fieldName, pat, opt); return Status::OK(); } Status JParse::regexPat(std::string* result) { MONGO_JSON_DEBUG(""); return chars(result, "/"); } Status JParse::regexOpt(std::string* result) { MONGO_JSON_DEBUG(""); return chars(result, "", JOPTIONS); } Status JParse::regexOptCheck(const StringData& opt) { MONGO_JSON_DEBUG("opt: " << opt); std::size_t i; for (i = 0; i < opt.size(); i++) { if (!match(opt[i], JOPTIONS)) { return parseError(string("Bad regex option: ") + opt[i]); } } return Status::OK(); } Status JParse::number(const StringData& fieldName, BSONObjBuilder& builder) { char* endptrll; char* endptrd; long long retll; double retd; // reset errno to make sure that we are getting it from strtod errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. retd = strtod(_input, &endptrd); // if pointer does not move, we found no digits if (_input == endptrd) { return parseError("Bad characters in value"); } if (errno == ERANGE) { return parseError("Value cannot fit in double"); } // reset errno to make sure that we are getting it from strtoll errno = 0; // SERVER-11920: We should use parseNumberFromString here, but that function requires that // we know ahead of time where the number ends, which is not currently the case. retll = strtoll(_input, &endptrll, 10); if (endptrll < endptrd || errno == ERANGE) { // The number either had characters only meaningful for a double or // could not fit in a 64 bit int MONGO_JSON_DEBUG("Type: double"); builder.append(fieldName, retd); } else if (retll == static_cast(retll)) { // The number can fit in a 32 bit int MONGO_JSON_DEBUG("Type: 32 bit int"); builder.append(fieldName, static_cast(retll)); } else { // The number can fit in a 64 bit int MONGO_JSON_DEBUG("Type: 64 bit int"); builder.append(fieldName, retll); } _input = endptrd; if (_input >= _input_end) { return parseError("Trailing number at end of input"); } return Status::OK(); } Status JParse::field(std::string* result) { MONGO_JSON_DEBUG(""); if (peekToken(DOUBLEQUOTE) || peekToken(SINGLEQUOTE)) { // Quoted key // TODO: make sure quoted field names cannot contain null characters return quotedString(result); } else { // Unquoted key // 'isspace()' takes an 'int' (signed), so (default signed) 'char's get sign-extended // and therefore 'corrupted' unless we force them to be unsigned ... 0x80 becomes // 0xffffff80 as seen by isspace when sign-extended ... we want it to be 0x00000080 while (_input < _input_end && isspace(*reinterpret_cast(_input))) { ++_input; } if (_input >= _input_end) { return parseError("Field name expected"); } if (!match(*_input, ALPHA "_$")) { return parseError("First character in field must be [A-Za-z$_]"); } return chars(result, "", ALPHA DIGIT "_$"); } } Status JParse::quotedString(std::string* result) { MONGO_JSON_DEBUG(""); if (readToken(DOUBLEQUOTE)) { Status ret = chars(result, "\""); if (ret != Status::OK()) { return ret; } if (!readToken(DOUBLEQUOTE)) { return parseError("Expecting '\"'"); } } else if (readToken(SINGLEQUOTE)) { Status ret = chars(result, "'"); if (ret != Status::OK()) { return ret; } if (!readToken(SINGLEQUOTE)) { return parseError("Expecting '''"); } } else { return parseError("Expecting quoted string"); } return Status::OK(); } /* * terminalSet are characters that signal end of string (e.g.) [ :\0] * allowedSet are the characters that are allowed, if this is set */ Status JParse::chars(std::string* result, const char* terminalSet, const char* allowedSet) { MONGO_JSON_DEBUG("terminalSet: " << terminalSet); if (_input >= _input_end) { return parseError("Unexpected end of input"); } const char* q = _input; while (q < _input_end && !match(*q, terminalSet)) { MONGO_JSON_DEBUG("q: " << q); if (allowedSet != NULL) { if (!match(*q, allowedSet)) { _input = q; return Status::OK(); } } if (0x00 <= *q && *q <= 0x1F) { return parseError("Invalid control character"); } if (*q == '\\' && q + 1 < _input_end) { switch (*(++q)) { // Escape characters allowed by the JSON spec case '"': result->push_back('"'); break; case '\'': result->push_back('\''); break; case '\\': result->push_back('\\'); break; case '/': result->push_back('/'); break; case 'b': result->push_back('\b'); break; case 'f': result->push_back('\f'); break; case 'n': result->push_back('\n'); break; case 'r': result->push_back('\r'); break; case 't': result->push_back('\t'); break; case 'u': { // expect 4 hexdigits // TODO: handle UTF-16 surrogate characters ++q; if (q + 4 >= _input_end) { return parseError("Expecting 4 hex digits"); } if (!isHexString(StringData(q, 4))) { return parseError("Expecting 4 hex digits"); } unsigned char first = fromHex(q); unsigned char second = fromHex(q += 2); const std::string& utf8str = encodeUTF8(first, second); for (unsigned int i = 0; i < utf8str.size(); i++) { result->push_back(utf8str[i]); } ++q; break; } // Vertical tab character. Not in JSON spec but allowed in // our implementation according to test suite. case 'v': result->push_back('\v'); break; // Escape characters we explicity disallow case 'x': return parseError("Hex escape not supported"); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': return parseError("Octal escape not supported"); // By default pass on the unescaped character default: result->push_back(*q); break; // TODO: check for escaped control characters } ++q; } else { result->push_back(*q++); } } if (q < _input_end) { _input = q; return Status::OK(); } return parseError("Unexpected end of input"); } std::string JParse::encodeUTF8(unsigned char first, unsigned char second) const { std::ostringstream oss; if (first == 0 && second < 0x80) { oss << second; } else if (first < 0x08) { oss << char(0xc0 | (first << 2 | second >> 6)); oss << char(0x80 | (~0xc0 & second)); } else { oss << char(0xe0 | (first >> 4)); oss << char(0x80 | (~0xc0 & (first << 2 | second >> 6))); oss << char(0x80 | (~0xc0 & second)); } return oss.str(); } inline bool JParse::peekToken(const char* token) { return readTokenImpl(token, false); } inline bool JParse::readToken(const char* token) { return readTokenImpl(token, true); } bool JParse::readTokenImpl(const char* token, bool advance) { MONGO_JSON_DEBUG("token: " << token); const char* check = _input; if (token == NULL) { return false; } // 'isspace()' takes an 'int' (signed), so (default signed) 'char's get sign-extended // and therefore 'corrupted' unless we force them to be unsigned ... 0x80 becomes // 0xffffff80 as seen by isspace when sign-extended ... we want it to be 0x00000080 while (check < _input_end && isspace(*reinterpret_cast(check))) { ++check; } while (*token != '\0') { if (check >= _input_end) { return false; } if (*token++ != *check++) { return false; } } if (advance) { _input = check; } return true; } bool JParse::readField(const StringData& expectedField) { MONGO_JSON_DEBUG("expectedField: " << expectedField); std::string nextField; nextField.reserve(FIELD_RESERVE_SIZE); Status ret = field(&nextField); if (ret != Status::OK()) { return false; } if (expectedField != nextField) { return false; } return true; } inline bool JParse::match(char matchChar, const char* matchSet) const { if (matchSet == NULL) { return true; } if (*matchSet == '\0') { return false; } return (strchr(matchSet, matchChar) != NULL); } bool JParse::isHexString(const StringData& str) const { MONGO_JSON_DEBUG("str: " << str); std::size_t i; for (i = 0; i < str.size(); i++) { if (!isxdigit(str[i])) { return false; } } return true; } bool JParse::isBase64String(const StringData& str) const { MONGO_JSON_DEBUG("str: " << str); std::size_t i; for (i = 0; i < str.size(); i++) { if (!match(str[i], base64::chars)) { return false; } } return true; } bool JParse::isArray() { return peekToken(LBRACKET); } BSONObj fromjson(const char* jsonString, int* len) { MONGO_JSON_DEBUG("jsonString: " << jsonString); if (jsonString[0] == '\0') { if (len) *len = 0; return BSONObj(); } JParse jparse(jsonString); BSONObjBuilder builder; Status ret = Status::OK(); try { ret = jparse.parse(builder); } catch (std::exception& e) { std::ostringstream message; message << "caught exception from within JSON parser: " << e.what(); throw MsgAssertionException(17031, message.str()); } if (ret != Status::OK()) { ostringstream message; message << "code " << ret.code() << ": " << ret.codeString() << ": " << ret.reason(); throw MsgAssertionException(16619, message.str()); } if (len) *len = jparse.offset(); return builder.obj(); } BSONObj fromjson(const std::string& str) { return fromjson(str.c_str()); } std::string tojson(const BSONObj& obj, JsonStringFormat format, bool pretty) { return obj.jsonString(format, pretty); } std::string tojson(const BSONArray& arr, JsonStringFormat format, bool pretty) { return arr.jsonString(format, pretty, true); } bool isArray(const StringData& str) { JParse parser(str); return parser.isArray(); } } /* namespace mongo */ mongo-cxx-driver-legacy-1.1.2/src/mongo/db/json.h000066400000000000000000000332611273231111400216020ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/bson/bsonobj.h" #include "mongo/base/status.h" #include "mongo/client/export_macros.h" namespace mongo { /** * Create a BSONObj from a JSON , * string. In addition to the JSON * extensions extensions described here * , this function * accepts unquoted field names and allows single quotes to optionally be * used when specifying field names and string values instead of double * quotes. JSON unicode escape sequences (of the form \uXXXX) are * converted to utf8. * * @throws MsgAssertionException if parsing fails. The message included with * this assertion includes the character offset where parsing failed. */ MONGO_CLIENT_API BSONObj MONGO_CLIENT_FUNC fromjson(const std::string& str); /** @param len will be size of JSON object in text chars. */ MONGO_CLIENT_API BSONObj MONGO_CLIENT_FUNC fromjson(const char* str, int* len = NULL); /** * Tests whether the JSON string is an Array. * * Useful for assigning the result of fromjson to the right object type. Either: * BSONObj * BSONArray * * Example: Using the method to select the proper type. * * If this method returns true, the user could store the result of fromjson * inside a BSONArray, rather than a BSONObj, in order to have it print as an * array when passed to tojson. * * @param obj The JSON string to test. */ MONGO_CLIENT_API bool isArray(const StringData& str); /** * Convert a BSONArray to a JSON string. * * @param arr The BSON Array. * @param format The JSON format (JS, TenGen, Strict). * @param pretty Enables pretty output. */ MONGO_CLIENT_API std::string tojson(const BSONArray& arr, JsonStringFormat format = Strict, bool pretty = false); /** * Convert a BSONObj to a JSON string. * * @param obj The BSON Object. * @param format The JSON format (JS, TenGen, Strict). * @param pretty Enables pretty output. */ MONGO_CLIENT_API std::string tojson(const BSONObj& obj, JsonStringFormat format = Strict, bool pretty = false); /** * Parser class. A BSONObj is constructed incrementally by passing a * BSONObjBuilder to the recursive parsing methods. The grammar for the * element parsed is described before each function. */ class JParse { public: explicit JParse(const StringData& str); /* * Notation: All-uppercase symbols denote non-terminals; all other * symbols are literals. */ /* * VALUE : * STRING * | NUMBER * | NUMBERINT * | NUMBERLONG * | OBJECT * | ARRAY * * | true * | false * | null * | undefined * * | NaN * | Infinity * | -Infinity * * | DATE * | TIMESTAMP * | REGEX * | OBJECTID * | DBREF * * | new CONSTRUCTOR */ private: Status value(const StringData& fieldName, BSONObjBuilder&); /* * OBJECT : * {} * | { MEMBERS } * | SPECIALOBJECT * * MEMBERS : * PAIR * | PAIR , MEMBERS * * PAIR : * FIELD : VALUE * * SPECIALOBJECT : * OIDOBJECT * | BINARYOBJECT * | DATEOBJECT * | TIMESTAMPOBJECT * | REGEXOBJECT * | REFOBJECT * | UNDEFINEDOBJECT * | NUMBERLONGOBJECT * | MINKEYOBJECT * | MAXKEYOBJECT * */ public: Status object(const StringData& fieldName, BSONObjBuilder&, bool subObj = true); Status parse(BSONObjBuilder& builder); bool isArray(); private: /* The following functions are called with the '{' and the first * field already parsed since they are both implied given the * context. */ /* * OIDOBJECT : * { FIELD("$oid") : <24 character hex string> } */ Status objectIdObject(const StringData& fieldName, BSONObjBuilder&); /* * BINARYOBJECT : * { FIELD("$binary") : , * FIELD("$type") : } */ Status binaryObject(const StringData& fieldName, BSONObjBuilder&); /* * DATEOBJECT : * { FIELD("$date") : <64 bit signed integer for milliseconds since epoch> } */ Status dateObject(const StringData& fieldName, BSONObjBuilder&); /* * TIMESTAMPOBJECT : * { FIELD("$timestamp") : { * FIELD("t") : <32 bit unsigned integer for seconds since epoch>, * FIELD("i") : <32 bit unsigned integer for the increment> } } */ Status timestampObject(const StringData& fieldName, BSONObjBuilder&); /* * NOTE: the rules for the body of the regex are different here, * since it is quoted instead of surrounded by slashes. * REGEXOBJECT : * { FIELD("$regex") : } * | { FIELD("$regex") : , * FIELD("$options") : } */ Status regexObject(const StringData& fieldName, BSONObjBuilder&); /* * REFOBJECT : * { FIELD("$ref") : , * FIELD("$id") : <24 character hex string> } * | { FIELD("$ref") : STRING , FIELD("$id") : OBJECTID } * | { FIELD("$ref") : STRING , FIELD("$id") : OIDOBJECT } */ Status dbRefObject(const StringData& fieldName, BSONObjBuilder&); /* * UNDEFINEDOBJECT : * { FIELD("$undefined") : true } */ Status undefinedObject(const StringData& fieldName, BSONObjBuilder&); /* * NUMBERLONGOBJECT : * { FIELD("$numberLong") : "" } */ Status numberLongObject(const StringData& fieldName, BSONObjBuilder&); /* * MINKEYOBJECT : * { FIELD("$minKey") : 1 } */ Status minKeyObject(const StringData& fieldName, BSONObjBuilder& builder); /* * MAXKEYOBJECT : * { FIELD("$maxKey") : 1 } */ Status maxKeyObject(const StringData& fieldName, BSONObjBuilder& builder); /* * ARRAY : * [] * | [ ELEMENTS ] * * ELEMENTS : * VALUE * | VALUE , ELEMENTS */ Status array(const StringData& fieldName, BSONObjBuilder&, bool subObj = true); /* * NOTE: Currently only Date can be preceded by the "new" keyword * CONSTRUCTOR : * DATE */ Status constructor(const StringData& fieldName, BSONObjBuilder&); /* The following functions only parse the body of the constructor * between the parentheses, not including the constructor name */ /* * DATE : * Date( <64 bit signed integer for milliseconds since epoch> ) */ Status date(const StringData& fieldName, BSONObjBuilder&); /* * TIMESTAMP : * Timestamp( <32 bit unsigned integer for seconds since epoch>, * <32 bit unsigned integer for the increment> ) */ Status timestamp(const StringData& fieldName, BSONObjBuilder&); /* * OBJECTID : * ObjectId( <24 character hex string> ) */ Status objectId(const StringData& fieldName, BSONObjBuilder&); /* * NUMBERLONG : * NumberLong( ) */ Status numberLong(const StringData& fieldName, BSONObjBuilder&); /* * NUMBERINT : * NumberInt( ) */ Status numberInt(const StringData& fieldName, BSONObjBuilder&); /* * DBREF : * Dbref( , <24 character hex string> ) */ Status dbRef(const StringData& fieldName, BSONObjBuilder&); /* * REGEX : * / REGEXCHARS / REGEXOPTIONS * * REGEXCHARS : * REGEXCHAR * | REGEXCHAR REGEXCHARS * * REGEXCHAR : * any-Unicode-character-except-/-or-\-or-CONTROLCHAR * | \" * | \' * | \\ * | \/ * | \b * | \f * | \n * | \r * | \t * | \v * | \u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT * | \any-Unicode-character-except-x-or-[0-7] * * REGEXOPTIONS : * REGEXOPTION * | REGEXOPTION REGEXOPTIONS * * REGEXOPTION : * g | i | m | s */ Status regex(const StringData& fieldName, BSONObjBuilder&); Status regexPat(std::string* result); Status regexOpt(std::string* result); Status regexOptCheck(const StringData& opt); /* * NUMBER : * * NOTE: Number parsing is based on standard library functions, not * necessarily on the JSON numeric grammar. * * Number as value - strtoll and strtod * Date - strtoll * Timestamp - strtoul for both timestamp and increment and '-' * before a number explicity disallowed */ Status number(const StringData& fieldName, BSONObjBuilder&); /* * FIELD : * STRING * | [a-zA-Z$_] FIELDCHARS * * FIELDCHARS : * [a-zA-Z0-9$_] * | [a-zA-Z0-9$_] FIELDCHARS */ Status field(std::string* result); /* * STRING : * " " * | ' ' * | " CHARS " * | ' CHARS ' */ Status quotedString(std::string* result); /* * CHARS : * CHAR * | CHAR CHARS * * Note: " or ' may be allowed depending on whether the string is * double or single quoted * * CHAR : * any-Unicode-character-except-"-or-'-or-\-or-CONTROLCHAR * | \" * | \' * | \\ * | \/ * | \b * | \f * | \n * | \r * | \t * | \v * | \u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT * | \any-Unicode-character-except-x-or-[0-9] * * HEXDIGIT : [0..9a..fA..F] * * per http://www.ietf.org/rfc/rfc4627.txt, control characters are * (U+0000 through U+001F). U+007F is not mentioned as a control * character. * CONTROLCHAR : [0x00..0x1F] * * If there is not an error, result will contain a null terminated * string, but there is no guarantee that it will not contain other * null characters. */ Status chars(std::string* result, const char* terminalSet, const char* allowedSet = NULL); /** * Converts the two byte Unicode code point to its UTF8 character * encoding representation. This function returns a string because * UTF8 encodings for code points from 0x0000 to 0xFFFF can range * from one to three characters. */ std::string encodeUTF8(unsigned char first, unsigned char second) const; /** * @return true if the given token matches the next non whitespace * sequence in our buffer, and false if the token doesn't match or * we reach the end of our buffer. Do not update the pointer to our * buffer (same as calling readTokenImpl with advance=false). */ inline bool peekToken(const char* token); /** * @return true if the given token matches the next non whitespace * sequence in our buffer, and false if the token doesn't match or * we reach the end of our buffer. Updates the pointer to our * buffer (same as calling readTokenImpl with advance=true). */ inline bool readToken(const char* token); /** * @return true if the given token matches the next non whitespace * sequence in our buffer, and false if the token doesn't match or * we reach the end of our buffer. Do not update the pointer to our * buffer if advance is false. */ bool readTokenImpl(const char* token, bool advance = true); /** * @return true if the next field in our stream matches field. * Handles single quoted, double quoted, and unquoted field names */ bool readField(const StringData& field); /** * @return true if matchChar is in matchSet * @return true if matchSet is NULL and false if it is an empty string */ bool match(char matchChar, const char* matchSet) const; /** * @return true if every character in the string is a hex digit */ bool isHexString(const StringData&) const; /** * @return true if every character in the string is a valid base64 * character */ bool isBase64String(const StringData&) const; /** * @return FailedToParse status with the given message and some * additional context information */ Status parseError(const StringData& msg); public: inline int offset() { return (_input - _buf); } private: /* * _buf - start of our input buffer * _input - cursor we advance in our input buffer * _input_end - sentinel for the end of our input buffer * * _buf is the null terminated buffer containing the JSON string we * are parsing. _input_end points to the null byte at the end of * the buffer. strtoll, strtol, and strtod will access the null * byte at the end of the buffer because they are assuming a c-style * string. */ const char* const _buf; const char* _input; const char* const _input_end; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/db/namespace_string-inl.h000066400000000000000000000122641273231111400247330ustar00rootroot00000000000000// namespacestring-inl.h /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/debug_util.h" namespace mongo { inline StringData NamespaceString::db() const { return _dotIndex == std::string::npos ? StringData() : StringData(_ns.c_str(), _dotIndex); } inline StringData NamespaceString::coll() const { return _dotIndex == std::string::npos ? StringData() : StringData(_ns.c_str() + _dotIndex + 1, _ns.size() - 1 - _dotIndex); } inline bool NamespaceString::normal(const StringData& ns) { if (ns.find('$') == std::string::npos) return true; return oplog(ns); } inline bool NamespaceString::oplog(const StringData& ns) { return ns.startsWith("local.oplog."); } inline bool NamespaceString::special(const StringData& ns) { return !normal(ns) || ns.substr(ns.find('.')).startsWith(".system."); } inline bool NamespaceString::validDBName(const StringData& db) { if (db.size() == 0 || db.size() > 64) return false; for (StringData::const_iterator iter = db.begin(), end = db.end(); iter != end; ++iter) { switch (*iter) { case '\0': case '/': case '\\': case '.': case ' ': case '"': return false; #ifdef _WIN32 // We prohibit all FAT32-disallowed characters on Windows case '*': case '<': case '>': case ':': case '|': case '?': return false; #endif default: continue; } } return true; } inline bool NamespaceString::validCollectionComponent(const StringData& ns) { size_t idx = ns.find('.'); if (idx == std::string::npos) return false; return validCollectionName(ns.substr(idx + 1)) || oplog(ns); } inline bool NamespaceString::validCollectionName(const StringData& coll) { if (coll.empty()) return false; if (coll[0] == '.') return false; for (StringData::const_iterator iter = coll.begin(), end = coll.end(); iter != end; ++iter) { switch (*iter) { case '\0': case '$': return false; default: continue; } } return true; } inline NamespaceString::NamespaceString() : _ns(), _dotIndex(0) {} inline NamespaceString::NamespaceString(const StringData& nsIn) { _ns = nsIn.toString(); // copy to our buffer _dotIndex = _ns.find('.'); } inline NamespaceString::NamespaceString(const StringData& dbName, const StringData& collectionName) : _ns(dbName.size() + collectionName.size() + 1, '\0') { uassert(17235, "'.' is an invalid character in a database name", dbName.find('.') == std::string::npos); uassert(17246, "Collection names cannot start with '.'", collectionName.empty() || collectionName[0] != '.'); std::string::iterator it = std::copy(dbName.begin(), dbName.end(), _ns.begin()); *it = '.'; ++it; it = std::copy(collectionName.begin(), collectionName.end(), it); _dotIndex = dbName.size(); dassert(it == _ns.end()); dassert(_ns[_dotIndex] == '.'); uassert(17295, "namespaces cannot have embedded null characters", _ns.find('\0') == std::string::npos); } inline int nsDBHash(const std::string& ns) { int hash = 7; for (size_t i = 0; i < ns.size(); i++) { if (ns[i] == '.') break; hash += 11 * (ns[i]); hash *= 3; } return hash; } inline bool nsDBEquals(const std::string& a, const std::string& b) { for (size_t i = 0; i < a.size(); i++) { if (a[i] == '.') { // b has to either be done or a '.' if (b.size() == i) return true; if (b[i] == '.') return true; return false; } // a is another character if (b.size() == i) return false; if (b[i] != a[i]) return false; } // a is done // make sure b is done if (b.size() == a.size() || b[a.size()] == '.') return true; return false; } /* future : this doesn't need to be an inline. */ inline std::string NamespaceString::getSisterNS(const StringData& local) const { verify(local.size() && local[0] != '.'); return db().toString() + "." + local.toString(); } inline std::string NamespaceString::getSystemIndexesCollection() const { return db().toString() + ".system.indexes"; } inline std::string NamespaceString::getCommandNS() const { return db().toString() + ".$cmd"; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/db/namespace_string.h000066400000000000000000000206231273231111400241510ustar00rootroot00000000000000// @file namespacestring.h /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/string_data.h" #include "mongo/util/assert_util.h" namespace mongo { /* in the mongo source code, "client" means "database". */ const size_t MaxDatabaseNameLen = 128; // max str len for the db name, including null char /** @return true if a client can modify this namespace even though it is under ".system." For example .system.users is ok for regular clients to update. @param write used when .system.js */ bool legalClientSystemNS(const StringData& ns, bool write); /* e.g. NamespaceString ns("acme.orders"); cout << ns.coll; // "orders" */ class NamespaceString { public: /** * Constructs an empty NamespaceString. */ NamespaceString(); /** * Constructs a NamespaceString from the fully qualified namespace named in "ns". */ explicit NamespaceString(const StringData& ns); /** * Constructs a NamespaceString for the given database and collection names. * "dbName" must not contain a ".", and "collectionName" must not start with one. */ NamespaceString(const StringData& dbName, const StringData& collectionName); /** * Note that these values are derived from the mmap_v1 implementation and that * is the only reason they are constrained as such. */ enum MaxNsLenValue { // Maximum possible length of name any namespace, including special ones like $extra. // This includes rum for the NUL byte so it can be used when sizing buffers. MaxNsLenWithNUL = 128, // MaxNsLenWithNUL excluding the NUL byte. Use this when comparing std::string lengths. MaxNsLen = MaxNsLenWithNUL - 1, // Maximum allowed length of fully qualified namespace name of any real collection. // Does not include NUL so it can be directly compared to std::string lengths. MaxNsCollectionLen = MaxNsLen - 7 /*strlen(".$extra")*/, }; StringData db() const; StringData coll() const; const std::string& ns() const { return _ns; } operator const std::string&() const { return ns(); } const std::string& toString() const { return ns(); } size_t size() const { return _ns.size(); } bool isSystem() const { return coll().startsWith("system."); } bool isSystemDotIndexes() const { return coll() == "system.indexes"; } bool isConfigDB() const { return db() == "config"; } bool isCommand() const { return coll() == "$cmd"; } bool isOplog() const { return oplog(_ns); } bool isSpecialCommand() const { return coll().startsWith("$cmd.sys"); } bool isSpecial() const { return special(_ns); } bool isNormal() const { return normal(_ns); } bool isListCollectionsGetMore() const; bool isListIndexesGetMore() const; /** * Given a NamespaceString for which isListIndexesGetMore() returns true, returns the * NamespaceString for the collection that the "listIndexesGetMore" targets. */ NamespaceString getTargetNSForListIndexesGetMore() const; /** * @return true if the namespace is valid. Special namespaces for internal use are considered as * valid. */ bool isValid() const { return validDBName(db()) && !coll().empty(); } bool operator==(const std::string& nsIn) const { return nsIn == _ns; } bool operator==(const StringData& nsIn) const { return nsIn == _ns; } bool operator==(const NamespaceString& nsIn) const { return nsIn._ns == _ns; } bool operator!=(const std::string& nsIn) const { return nsIn != _ns; } bool operator!=(const NamespaceString& nsIn) const { return nsIn._ns != _ns; } bool operator<(const NamespaceString& rhs) const { return _ns < rhs._ns; } /** ( foo.bar ).getSisterNS( "blah" ) == foo.blah */ std::string getSisterNS(const StringData& local) const; // @return db() + ".system.indexes" std::string getSystemIndexesCollection() const; // @return db() + ".$cmd" std::string getCommandNS() const; /** * @return true if ns is 'normal'. A "$" is used for namespaces holding index data, * which do not contain BSON objects in their records. ("oplog.$main" is the exception) */ static bool normal(const StringData& ns); /** * @return true if the ns is an oplog one, otherwise false. */ static bool oplog(const StringData& ns); static bool special(const StringData& ns); /** * samples: * good * foo * bar * foo-bar * bad: * foo bar * foo.bar * foo"bar * * @param db - a possible database name * @return if db is an allowed database name */ static bool validDBName(const StringData& dbin); /** * Takes a fully qualified namespace (ie dbname.collectionName), and returns true if * the collection name component of the namespace is valid. * samples: * good: * foo.bar * bad: * foo. * * @param ns - a full namespace (a.b) * @return if db.coll is an allowed collection name */ static bool validCollectionComponent(const StringData& ns); /** * Takes a collection name and returns true if it is a valid collection name. * samples: * good: * foo * system.indexes * bad: * $foo * @param coll - a collection name component of a namespace * @return if the input is a valid collection name */ static bool validCollectionName(const StringData& coll); private: std::string _ns; size_t _dotIndex; }; // "database.a.b.c" -> "database" inline StringData nsToDatabaseSubstring(const StringData& ns) { size_t i = ns.find('.'); if (i == std::string::npos) { massert(10078, "nsToDatabase: db too long", ns.size() < MaxDatabaseNameLen); return ns; } massert(10088, "nsToDatabase: db too long", i < static_cast(MaxDatabaseNameLen)); return ns.substr(0, i); } // "database.a.b.c" -> "database" inline void nsToDatabase(const StringData& ns, char* database) { StringData db = nsToDatabaseSubstring(ns); db.copyTo(database, true); } // TODO: make this return a StringData inline std::string nsToDatabase(const StringData& ns) { return nsToDatabaseSubstring(ns).toString(); } // "database.a.b.c" -> "a.b.c" inline StringData nsToCollectionSubstring(const StringData& ns) { size_t i = ns.find('.'); massert(16886, "nsToCollectionSubstring: no .", i != std::string::npos); return ns.substr(i + 1); } /** * foo = false * foo. = false * foo.a = true */ inline bool nsIsFull(const StringData& ns) { size_t i = ns.find('.'); if (i == std::string::npos) return false; if (i == ns.size() - 1) return false; return true; } /** * foo = true * foo. = false * foo.a = false */ inline bool nsIsDbOnly(const StringData& ns) { size_t i = ns.find('.'); if (i == std::string::npos) return true; return false; } /** * NamespaceDBHash and NamespaceDBEquals allow you to do something like * unordered_map * and use the full namespace for the string * but comparisons are done only on the db piece */ /** * this can change, do not store on disk */ int nsDBHash(const std::string& ns); bool nsDBEquals(const std::string& a, const std::string& b); struct NamespaceDBHash { int operator()(const std::string& ns) const { return nsDBHash(ns); } }; struct NamespaceDBEquals { bool operator()(const std::string& a, const std::string& b) const { return nsDBEquals(a, b); } }; } #include "mongo/db/namespace_string-inl.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/db/namespace_string_test.cpp000066400000000000000000000152201273231111400255400ustar00rootroot00000000000000// namespacestring_test.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/unittest/unittest.h" #include "mongo/db/namespace_string.h" namespace mongo { TEST(NamespaceStringTest, Normal) { ASSERT(NamespaceString::normal("a")); ASSERT(NamespaceString::normal("a.b")); ASSERT(NamespaceString::normal("a.b.c")); ASSERT(!NamespaceString::normal("a.b.$c")); ASSERT(!NamespaceString::normal("a.b.$.c")); ASSERT(NamespaceString::normal("local.oplog.$main")); ASSERT(NamespaceString::normal("local.oplog.rs")); } TEST(NamespaceStringTest, Oplog) { ASSERT(!NamespaceString::oplog("a")); ASSERT(!NamespaceString::oplog("a.b")); ASSERT(NamespaceString::oplog("local.oplog.rs")); ASSERT(NamespaceString::oplog("local.oplog.foo")); ASSERT(NamespaceString::oplog("local.oplog.$main")); ASSERT(NamespaceString::oplog("local.oplog.$foo")); } TEST(NamespaceStringTest, Special) { ASSERT(NamespaceString::special("a.$.b")); ASSERT(NamespaceString::special("a.system.foo")); ASSERT(!NamespaceString::special("a.foo")); ASSERT(!NamespaceString::special("a.foo.system.bar")); ASSERT(!NamespaceString::special("a.systemfoo")); } TEST(NamespaceStringTest, DatabaseValidNames) { ASSERT(NamespaceString::validDBName("foo")); ASSERT(!NamespaceString::validDBName("foo/bar")); ASSERT(!NamespaceString::validDBName("foo bar")); ASSERT(!NamespaceString::validDBName("foo.bar")); ASSERT(!NamespaceString::validDBName("foo.bar")); ASSERT(!NamespaceString::validDBName("foo\\bar")); ASSERT(!NamespaceString::validDBName("foo\"bar")); ASSERT(!NamespaceString::validDBName(StringData("a\0b", StringData::LiteralTag()))); #ifdef _WIN32 ASSERT(!NamespaceString::validDBName("foo*bar")); ASSERT(!NamespaceString::validDBName("foobar")); ASSERT(!NamespaceString::validDBName("foo:bar")); ASSERT(!NamespaceString::validDBName("foo|bar")); ASSERT(!NamespaceString::validDBName("foo?bar")); #endif ASSERT(NamespaceString::normal("asdads")); ASSERT(!NamespaceString::normal("asda$ds")); ASSERT(NamespaceString::normal("local.oplog.$main")); } TEST(NamespaceStringTest, CollectionComponentValidNames) { ASSERT(NamespaceString::validCollectionComponent("a.b")); ASSERT(NamespaceString::validCollectionComponent("a.b")); ASSERT(!NamespaceString::validCollectionComponent("a.")); ASSERT(!NamespaceString::validCollectionComponent("a..foo")); ASSERT(NamespaceString::validCollectionComponent("a.b.")); // TODO: should this change? } TEST(NamespaceStringTest, CollectionValidNames) { ASSERT(NamespaceString::validCollectionName("a")); ASSERT(NamespaceString::validCollectionName("a.b")); ASSERT(NamespaceString::validCollectionName("a.")); // TODO: should this change? ASSERT(NamespaceString::validCollectionName("a.b.")); // TODO: should this change? ASSERT(!NamespaceString::validCollectionName(".a")); ASSERT(!NamespaceString::validCollectionName("$a")); ASSERT(!NamespaceString::validCollectionName("a$b")); ASSERT(!NamespaceString::validCollectionName("")); ASSERT(!NamespaceString::validCollectionName(StringData("a\0b", StringData::LiteralTag()))); } TEST(NamespaceStringTest, DBHash) { ASSERT_EQUALS(nsDBHash("foo"), nsDBHash("foo")); ASSERT_EQUALS(nsDBHash("foo"), nsDBHash("foo.a")); ASSERT_EQUALS(nsDBHash("foo"), nsDBHash("foo.")); ASSERT_EQUALS(nsDBHash(""), nsDBHash("")); ASSERT_EQUALS(nsDBHash(""), nsDBHash(".a")); ASSERT_EQUALS(nsDBHash(""), nsDBHash(".")); ASSERT_NOT_EQUALS(nsDBHash("foo"), nsDBHash("food")); ASSERT_NOT_EQUALS(nsDBHash("foo."), nsDBHash("food")); ASSERT_NOT_EQUALS(nsDBHash("foo.d"), nsDBHash("food")); } #define testEqualsBothWays(X, Y) \ ASSERT_TRUE(nsDBEquals((X), (Y))); \ ASSERT_TRUE(nsDBEquals((Y), (X))); #define testNotEqualsBothWays(X, Y) \ ASSERT_FALSE(nsDBEquals((X), (Y))); \ ASSERT_FALSE(nsDBEquals((Y), (X))); TEST(NamespaceStringTest, DBEquals) { testEqualsBothWays("foo", "foo"); testEqualsBothWays("foo", "foo.a"); testEqualsBothWays("foo.a", "foo.a"); testEqualsBothWays("foo.a", "foo.b"); testEqualsBothWays("", ""); testEqualsBothWays("", "."); testEqualsBothWays("", ".x"); testNotEqualsBothWays("foo", "bar"); testNotEqualsBothWays("foo", "food"); testNotEqualsBothWays("foo.", "food"); testNotEqualsBothWays("", "x"); testNotEqualsBothWays("", "x."); testNotEqualsBothWays("", "x.y"); testNotEqualsBothWays(".", "x"); testNotEqualsBothWays(".", "x."); testNotEqualsBothWays(".", "x.y"); } TEST(NamespaceStringTest, nsToDatabase1) { ASSERT_EQUALS("foo", nsToDatabaseSubstring("foo.bar")); ASSERT_EQUALS("foo", nsToDatabaseSubstring("foo")); ASSERT_EQUALS("foo", nsToDatabase("foo.bar")); ASSERT_EQUALS("foo", nsToDatabase("foo")); ASSERT_EQUALS("foo", nsToDatabase(std::string("foo.bar"))); ASSERT_EQUALS("foo", nsToDatabase(std::string("foo"))); } TEST(NamespaceStringTest, nsToDatabase2) { char buf[MaxDatabaseNameLen]; nsToDatabase("foo.bar", buf); ASSERT_EQUALS('f', buf[0]); ASSERT_EQUALS('o', buf[1]); ASSERT_EQUALS('o', buf[2]); ASSERT_EQUALS(0, buf[3]); nsToDatabase("bar", buf); ASSERT_EQUALS('b', buf[0]); ASSERT_EQUALS('a', buf[1]); ASSERT_EQUALS('r', buf[2]); ASSERT_EQUALS(0, buf[3]); } TEST(NamespaceStringTest, NamespaceStringParse1) { NamespaceString ns("a.b"); ASSERT_EQUALS((std::string) "a", ns.db()); ASSERT_EQUALS((std::string) "b", ns.coll()); } TEST(NamespaceStringTest, NamespaceStringParse2) { NamespaceString ns("a.b.c"); ASSERT_EQUALS((std::string) "a", ns.db()); ASSERT_EQUALS((std::string) "b.c", ns.coll()); } TEST(NamespaceStringTest, NamespaceStringParse3) { NamespaceString ns("abc"); ASSERT_EQUALS((std::string) "", ns.db()); ASSERT_EQUALS((std::string) "", ns.coll()); } TEST(NamespaceStringTest, NamespaceStringParse4) { NamespaceString ns("abc."); ASSERT_EQUALS((std::string) "abc", ns.db()); ASSERT_EQUALS((std::string) "", ns.coll()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/db/repl/000077500000000000000000000000001273231111400214155ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/db/repl/member_state.h000066400000000000000000000062771273231111400242510ustar00rootroot00000000000000/* * Copyright (C) 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** replica set member */ #pragma once #include namespace mongo { namespace repl { /* RS_STARTUP serving still starting up, or still trying to initiate the set RS_PRIMARY this server thinks it is primary RS_SECONDARY this server thinks it is a secondary (slave mode) RS_RECOVERING recovering/resyncing; after recovery usually auto-transitions to secondary RS_STARTUP2 loaded config, still determining who is primary State -> integer mappings are reserved forever. Do not change them or delete them, except to update RS_MAX when introducing new states. */ struct MemberState { enum MS { RS_STARTUP = 0, RS_PRIMARY = 1, RS_SECONDARY = 2, RS_RECOVERING = 3, RS_STARTUP2 = 5, RS_UNKNOWN = 6, /* remote node not yet reached */ RS_ARBITER = 7, RS_DOWN = 8, /* node not reachable for a report */ RS_ROLLBACK = 9, RS_REMOVED = 10, /* node removed from replica set */ RS_MAX = 10 } s; MemberState(MS ms = RS_UNKNOWN) : s(ms) {} explicit MemberState(int ms) : s((MS)ms) {} bool startup() const { return s == RS_STARTUP; } bool primary() const { return s == RS_PRIMARY; } bool secondary() const { return s == RS_SECONDARY; } bool recovering() const { return s == RS_RECOVERING; } bool startup2() const { return s == RS_STARTUP2; } bool rollback() const { return s == RS_ROLLBACK; } bool readable() const { return s == RS_PRIMARY || s == RS_SECONDARY; } bool removed() const { return s == RS_REMOVED; } bool arbiter() const { return s == RS_ARBITER; } std::string toString() const; bool operator==(const MemberState& r) const { return s == r.s; } bool operator!=(const MemberState& r) const { return s != r.s; } }; inline std::string MemberState::toString() const { switch (s) { case RS_STARTUP: return "STARTUP"; case RS_PRIMARY: return "PRIMARY"; case RS_SECONDARY: return "SECONDARY"; case RS_RECOVERING: return "RECOVERING"; case RS_STARTUP2: return "STARTUP2"; case RS_ARBITER: return "ARBITER"; case RS_DOWN: return "DOWN"; case RS_ROLLBACK: return "ROLLBACK"; case RS_UNKNOWN: return "UNKNOWN"; case RS_REMOVED: return "REMOVED"; } return ""; } } // namespace repl } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/000077500000000000000000000000001273231111400215365ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/jsobjtests.cpp000066400000000000000000002121261273231111400244400ustar00rootroot00000000000000// jsobjtests.cpp - Tests for jsobj.{h,cpp} code // /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include #include "mongo/bson/util/builder.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/platform/float_utils.h" #include "mongo/unittest/unittest.h" #include "mongo/util/embedded_builder.h" #include "mongo/util/log.h" #include "mongo/util/stringutils.h" namespace mongo { using std::endl; using std::string; typedef std::map BSONMap; inline BSONMap bson2map(const BSONObj& obj) { BSONMap m; BSONObjIterator it(obj); while (it.more()) { BSONElement e = it.next(); m[e.fieldName()] = e; } return m; } void dotted2nested(BSONObjBuilder& b, const BSONObj& obj) { // use map to sort fields BSONMap sorted = bson2map(obj); EmbeddedBuilder eb(&b); for (BSONMap::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { eb.appendAs(it->second, it->first); } eb.done(); } // {a.b:1} -> {a: {b:1}} void dotted2nested(BSONObjBuilder& b, const BSONObj& obj); inline BSONObj dotted2nested(const BSONObj& obj) { BSONObjBuilder b; dotted2nested(b, obj); return b.obj(); } void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base) { BSONObjIterator it(obj); while (it.more()) { BSONElement e = it.next(); if (e.type() == Object) { string newbase = base + e.fieldName() + "."; nested2dotted(b, e.embeddedObject(), newbase); } else { string newbase = base + e.fieldName(); b.appendAs(e, newbase); } } } // {a: {b:1}} -> {a.b:1} void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const std::string& base = ""); inline BSONObj nested2dotted(const BSONObj& obj) { BSONObjBuilder b; nested2dotted(b, obj); return b.obj(); } FieldCompareResult compareDottedFieldNames(const string& l, const string& r, const LexNumCmp& cmp) { static int maxLoops = 1024 * 1024; size_t lstart = 0; size_t rstart = 0; for (int i = 0; i < maxLoops; i++) { size_t a = l.find('.', lstart); size_t b = r.find('.', rstart); size_t lend = a == string::npos ? l.size() : a; size_t rend = b == string::npos ? r.size() : b; const string& c = l.substr(lstart, lend - lstart); const string& d = r.substr(rstart, rend - rstart); int x = cmp.cmp(c.c_str(), d.c_str()); if (x < 0) return LEFT_BEFORE; if (x > 0) return RIGHT_BEFORE; lstart = lend + 1; rstart = rend + 1; if (lstart >= l.size()) { if (rstart >= r.size()) return SAME; return RIGHT_SUBFIELD; } if (rstart >= r.size()) return LEFT_SUBFIELD; } log() << "compareDottedFieldNames ERROR l: " << l << " r: " << r << " TOO MANY LOOPS" << endl; verify(0); return SAME; // will never get here } } // namespace mongo namespace JsobjTests { using namespace std; // void keyTest(const BSONObj& o, bool mustBeCompact = false) { // static KeyV1Owned *kLast; // static BSONObj last; // KeyV1Owned *key = new KeyV1Owned(o); // KeyV1Owned& k = *key; // ASSERT( !mustBeCompact || k.isCompactFormat() ); // BSONObj x = k.toBson(); // int res = o.woCompare(x, BSONObj(), [>considerfieldname<]false); // if( res ) { // cout << o.toString() << endl; // k.toBson(); // cout << x.toString() << endl; // o.woCompare(x, BSONObj(), [>considerfieldname<]false); // ASSERT( res == 0 ); //} // ASSERT( k.woEqual(k) ); // ASSERT( !k.isCompactFormat() || k.dataSize() < o.objsize() ); //{ //// check BSONObj::equal. this part not a KeyV1 test. // int res = o.woCompare(last); // ASSERT( (res==0) == o.equal(last) ); //} // if( kLast ) { // int r1 = o.woCompare(last, BSONObj(), false); // int r2 = k.woCompare(*kLast, Ordering::make(BSONObj())); // bool ok = (r1<0 && r2<0) || (r1>0&&r2>0) || r1==r2; // if( !ok ) { // cout << "r1r2 " << r1 << ' ' << r2 << endl; // cout << "o:" << o.toString() << endl; // cout << "last:" << last.toString() << endl; // cout << "k:" << k.toString() << endl; // cout << "kLast:" << kLast->toString() << endl; // int r3 = k.woCompare(*kLast, Ordering::make(BSONObj())); // cout << r3 << endl; //} // ASSERT(ok); // if( k.isCompactFormat() && kLast->isCompactFormat() ) { // only check if not bson as bson woEqual // is broken! (or was may2011) // if( k.woEqual(*kLast) != (r2 == 0) ) { // check woEqual matches // cout << r2 << endl; // cout << k.toString() << endl; // cout << kLast->toString() << endl; // k.woEqual(*kLast); // ASSERT(false); //} //} //} // delete kLast; // kLast = key; // last = o.getOwned(); //} class BufBuilderBasic { public: void run() { { BufBuilder b(0); b.appendStr("foo"); ASSERT_EQUALS(4, b.len()); ASSERT(strcmp("foo", b.buf()) == 0); } { mongo::StackBufBuilder b; b.appendStr("foo"); ASSERT_EQUALS(4, b.len()); ASSERT(strcmp("foo", b.buf()) == 0); } } }; DBTEST_SHIM_TEST(BufBuilderBasic); class BufBuilderReallocLimit { public: void run() { BufBuilder b; unsigned int written = 0; try { for (; written <= 64 * 1024 * 1024 + 1; ++written) // (re)alloc past the buffer 64mb limit b.appendStr("a"); } catch (const AssertionException&) { } // assert half of max buffer size was allocated before exception is thrown ASSERT(written == mongo::BufferMaxSize / 2); } }; DBTEST_SHIM_TEST(BufBuilderReallocLimit); class BSONElementBasic { public: void run() { ASSERT_EQUALS(1, BSONElement().size()); BSONObj x; ASSERT_EQUALS(1, x.firstElement().size()); } }; DBTEST_SHIM_TEST(BSONElementBasic); namespace BSONObjTests { class Create { public: void run() { BSONObj b; ASSERT_EQUALS(0, b.nFields()); } }; DBTEST_SHIM_TEST(Create); class Base { protected: static BSONObj basic(const char* name, int val) { BSONObjBuilder b; b.append(name, val); return b.obj(); } static BSONObj basic(const char* name, vector val) { BSONObjBuilder b; b.append(name, val); return b.obj(); } template static BSONObj basic(const char* name, T val) { BSONObjBuilder b; b.append(name, val); return b.obj(); } }; class WoCompareBasic : public Base { public: void run() { ASSERT(basic("a", 1).woCompare(basic("a", 1)) == 0); ASSERT(basic("a", 2).woCompare(basic("a", 1)) > 0); ASSERT(basic("a", 1).woCompare(basic("a", 2)) < 0); // field name comparison ASSERT(basic("a", 1).woCompare(basic("b", 1)) < 0); } }; DBTEST_SHIM_TEST(WoCompareBasic); class IsPrefixOf : public Base { public: void run() { { BSONObj k = BSON("x" << 1); verify(!k.isPrefixOf(BSON("a" << 1))); verify(k.isPrefixOf(BSON("x" << 1))); verify(k.isPrefixOf(BSON("x" << 1 << "a" << 1))); verify(!k.isPrefixOf(BSON("a" << 1 << "x" << 1))); } { BSONObj k = BSON("x" << 1 << "y" << 1); verify(!k.isPrefixOf(BSON("x" << 1))); verify(!k.isPrefixOf(BSON("x" << 1 << "z" << 1))); verify(k.isPrefixOf(BSON("x" << 1 << "y" << 1))); verify(k.isPrefixOf(BSON("x" << 1 << "y" << 1 << "z" << 1))); } { BSONObj k = BSON("x" << 1); verify(!k.isPrefixOf(BSON("x" << "hi"))); verify(k.isPrefixOf(BSON("x" << 1 << "a" << "hi"))); } { BSONObj k = BSON("x" << 1); verify(k.isFieldNamePrefixOf(BSON("x" << "hi"))); verify(!k.isFieldNamePrefixOf(BSON("a" << 1))); } } }; DBTEST_SHIM_TEST(IsPrefixOf); class NumericCompareBasic : public Base { public: void run() { ASSERT(basic("a", 1).woCompare(basic("a", 1.0)) == 0); } }; DBTEST_SHIM_TEST(NumericCompareBasic); class WoCompareEmbeddedObject : public Base { public: void run() { ASSERT(basic("a", basic("b", 1)).woCompare(basic("a", basic("b", 1.0))) == 0); ASSERT(basic("a", basic("b", 1)).woCompare(basic("a", basic("b", 2))) < 0); } }; DBTEST_SHIM_TEST(WoCompareEmbeddedObject); class WoCompareEmbeddedArray : public Base { public: void run() { vector i; i.push_back(1); i.push_back(2); vector d; d.push_back(1); d.push_back(2); ASSERT(basic("a", i).woCompare(basic("a", d)) == 0); vector j; j.push_back(1); j.push_back(3); ASSERT(basic("a", i).woCompare(basic("a", j)) < 0); } }; DBTEST_SHIM_TEST(WoCompareEmbeddedArray); class WoCompareOrdered : public Base { public: void run() { ASSERT(basic("a", 1).woCompare(basic("a", 1), basic("a", 1)) == 0); ASSERT(basic("a", 2).woCompare(basic("a", 1), basic("a", 1)) > 0); ASSERT(basic("a", 1).woCompare(basic("a", 2), basic("a", 1)) < 0); ASSERT(basic("a", 1).woCompare(basic("a", 1), basic("a", -1)) == 0); ASSERT(basic("a", 2).woCompare(basic("a", 1), basic("a", -1)) < 0); ASSERT(basic("a", 1).woCompare(basic("a", 2), basic("a", -1)) > 0); } }; DBTEST_SHIM_TEST(WoCompareOrdered); class WoCompareDifferentLength : public Base { public: void run() { ASSERT(BSON("a" << 1).woCompare(BSON("a" << 1 << "b" << 1)) < 0); ASSERT(BSON("a" << 1 << "b" << 1).woCompare(BSON("a" << 1)) > 0); } }; DBTEST_SHIM_TEST(WoCompareDifferentLength); class WoSortOrder : public Base { public: void run() { ASSERT(BSON("a" << 1).woSortOrder(BSON("a" << 2), BSON("b" << 1 << "a" << 1)) < 0); ASSERT(fromjson("{a:null}").woSortOrder(BSON("b" << 1), BSON("a" << 1)) == 0); } }; DBTEST_SHIM_TEST(WoSortOrder); class MultiKeySortOrder : public Base { public: void run() { ASSERT(BSON("x" << "a") .woCompare(BSON("x" << "b")) < 0); ASSERT(BSON("x" << "b") .woCompare(BSON("x" << "a")) > 0); ASSERT(BSON("x" << "a" << "y" << "a") .woCompare(BSON("x" << "a" << "y" << "b")) < 0); ASSERT(BSON("x" << "a" << "y" << "a") .woCompare(BSON("x" << "b" << "y" << "a")) < 0); ASSERT(BSON("x" << "a" << "y" << "a") .woCompare(BSON("x" << "b")) < 0); ASSERT(BSON("x" << "c") .woCompare(BSON("x" << "b" << "y" << "h")) > 0); ASSERT(BSON("x" << "b" << "y" << "b") .woCompare(BSON("x" << "c")) < 0); BSONObj key = BSON("x" << 1 << "y" << 1); ASSERT(BSON("x" << "c") .woSortOrder(BSON("x" << "b" << "y" << "h"), key) > 0); ASSERT(BSON("x" << "b" << "y" << "b") .woCompare(BSON("x" << "c"), key) < 0); key = BSON("" << 1 << "" << 1); ASSERT(BSON("" << "c") .woSortOrder(BSON("" << "b" << "" << "h"), key) > 0); ASSERT(BSON("" << "b" << "" << "b") .woCompare(BSON("" << "c"), key) < 0); { // test a big key string x(2000, 'z'); BSONObj o = BSON("q" << x); // keyTest(o, false); } { string y(200, 'w'); BSONObjBuilder b; for (int i = 0; i < 10; i++) { b.append("x", y); } // keyTest(b.obj(), true); } { double nan = numeric_limits::quiet_NaN(); BSONObj o = BSON("y" << nan); // keyTest(o); } { BSONObjBuilder b; b.append("", "c"); b.appendNull(""); BSONObj o = b.obj(); // keyTest(o); ASSERT(o.woSortOrder(BSON("" << "b" << "" << "h"), key) > 0); ASSERT(BSON("" << "b" << "" << "h").woSortOrder(o, key) < 0); } ASSERT(BSON("" << "a") .woCompare(BSON("" << "a" << "" << "c")) < 0); { BSONObjBuilder b; b.append("", "a"); b.appendNull(""); ASSERT(b.obj().woCompare(BSON("" << "a" << "" << "c")) < 0); // SERVER-282 } } }; DBTEST_SHIM_TEST(MultiKeySortOrder); class Nan : public Base { public: void run() { double inf = numeric_limits::infinity(); double nan = numeric_limits::quiet_NaN(); double nan2 = numeric_limits::signaling_NaN(); ASSERT(isNaN(nan)); ASSERT(isNaN(nan2)); ASSERT(!isNaN(inf)); ASSERT(BSON("a" << inf).woCompare(BSON("a" << inf)) == 0); ASSERT(BSON("a" << inf).woCompare(BSON("a" << 1)) > 0); ASSERT(BSON("a" << 1).woCompare(BSON("a" << inf)) < 0); ASSERT(BSON("a" << nan).woCompare(BSON("a" << nan)) == 0); ASSERT(BSON("a" << nan).woCompare(BSON("a" << 1)) < 0); ASSERT(BSON("a" << nan).woCompare(BSON("a" << 5000000000LL)) < 0); //{ // KeyV1Owned a( BSON( "a" << nan ) ); // KeyV1Owned b( BSON( "a" << 1 ) ); // Ordering o = Ordering::make(BSON("a"<<1)); // ASSERT( a.woCompare(b, o) < 0 ); //} ASSERT(BSON("a" << 1).woCompare(BSON("a" << nan)) > 0); ASSERT(BSON("a" << nan2).woCompare(BSON("a" << nan2)) == 0); ASSERT(BSON("a" << nan2).woCompare(BSON("a" << 1)) < 0); ASSERT(BSON("a" << 1).woCompare(BSON("a" << nan2)) > 0); ASSERT(BSON("a" << inf).woCompare(BSON("a" << nan)) > 0); ASSERT(BSON("a" << inf).woCompare(BSON("a" << nan2)) > 0); ASSERT(BSON("a" << nan).woCompare(BSON("a" << nan2)) == 0); } }; DBTEST_SHIM_TEST(Nan); class AsTempObj { public: void run() { { BSONObjBuilder bb; bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT(tmp == BSON("a" << 1)); bb << "b" << 2; BSONObj obj = bb.obj(); ASSERT_EQUALS(obj.objsize(), 4 + (1 + 2 + 4) + (1 + 2 + 4) + 1); ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT(obj == BSON("a" << 1 << "b" << 2)); } { BSONObjBuilder bb; bb << "a" << GT << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT(tmp == BSON("a" << BSON("$gt" << 1))); bb << "b" << LT << 2; BSONObj obj = bb.obj(); ASSERT(obj.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT(obj == BSON("a" << BSON("$gt" << 1) << "b" << BSON("$lt" << 2))); } { BSONObjBuilder bb(32); bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); ASSERT(tmp.valid()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT(tmp == BSON("a" << 1)); // force a realloc BSONArrayBuilder arr; for (int i = 0; i < 10000; i++) { arr << i; } bb << "b" << arr.arr(); BSONObj obj = bb.obj(); ASSERT(obj.valid()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); } } }; DBTEST_SHIM_TEST(AsTempObj); struct AppendIntOrLL { void run() { const long long billion = 1000 * 1000 * 1000; long long n = 0x3333111122224444LL; { double d = (double)n; BSONObj a = BSON("x" << n); BSONObj b = BSON("x" << d); long long back = (long long)d; // 3719 ////// int res = a.woCompare(b); ASSERT(n > back); // ASSERT( res > 0 ); // SERVER-3719 // keyTest(a, false); // KeyV1Owned A(a); // KeyV1Owned B(b); // 3719 ////// int res2 = A.woCompare(B, Ordering::make(BSONObj())); // ASSERT( res2 > 0 ); // SERVER-3719 // fixing requires an index v# change. cout << "todo fix SERVER-3719 and uncomment test in AppendIntOrLL" << endl; n++; } //{ // BSONObjBuilder b; // b.appendIntOrLL("L4", -4*billion); // keyTest(b.obj()); // keyTest( BSON("" << billion) ); //} BSONObjBuilder b; b.appendIntOrLL("i1", 1); b.appendIntOrLL("i2", -1); b.appendIntOrLL("i3", 1 * billion); b.appendIntOrLL("i4", -1 * billion); b.appendIntOrLL("L1", 2 * billion); b.appendIntOrLL("L2", -2 * billion); b.appendIntOrLL("L3", 4 * billion); b.appendIntOrLL("L4", -4 * billion); b.appendIntOrLL("L5", 16 * billion); b.appendIntOrLL("L6", -16 * billion); BSONObj o = b.obj(); // keyTest(o); ASSERT(o["i1"].type() == NumberInt); ASSERT(o["i1"].number() == 1); ASSERT(o["i2"].type() == NumberInt); ASSERT(o["i2"].number() == -1); ASSERT(o["i3"].type() == NumberInt); ASSERT(o["i3"].number() == 1 * billion); ASSERT(o["i4"].type() == NumberInt); ASSERT(o["i4"].number() == -1 * billion); ASSERT(o["L1"].isNumber()); ASSERT(o["L1"].number() == 2 * billion); ASSERT(o["L2"].isNumber()); ASSERT(o["L2"].number() == -2 * billion); ASSERT(o["L3"].type() == NumberLong); ASSERT(o["L3"].number() == 4 * billion); ASSERT(o["L4"].type() == NumberLong); ASSERT(o["L4"].number() == -4 * billion); ASSERT(o["L5"].type() == NumberLong); ASSERT(o["L5"].number() == 16 * billion); ASSERT(o["L6"].type() == NumberLong); ASSERT(o["L6"].number() == -16 * billion); } }; DBTEST_SHIM_TEST(AppendIntOrLL); struct AppendNumber { void run() { BSONObjBuilder b; b.appendNumber("a", 5); b.appendNumber("b", 5.5); b.appendNumber("c", (1024LL * 1024 * 1024) - 1); b.appendNumber("d", (1024LL * 1024 * 1024 * 1024) - 1); b.appendNumber("e", 1024LL * 1024 * 1024 * 1024 * 1024 * 1024); BSONObj o = b.obj(); // keyTest(o); ASSERT(o["a"].type() == NumberInt); ASSERT(o["b"].type() == NumberDouble); ASSERT(o["c"].type() == NumberInt); ASSERT(o["d"].type() == NumberDouble); ASSERT(o["e"].type() == NumberLong); } }; DBTEST_SHIM_TEST(AppendNumber); class ToStringArray { public: void run() { string spec = "{ a: [ \"a\", \"b\" ] }"; ASSERT_EQUALS(spec, fromjson(spec).toString()); BSONObj x = BSON("a" << "astring" << "b" << "str"); // keyTest(x); // keyTest(x); BSONObj y = BSON("a" << "astring" << "b" << "stra"); // keyTest(y); y = BSON("a" << ""); // keyTest(y); // keyTest( BSON("abc" << true ) ); // keyTest( BSON("abc" << false ) ); // keyTest( BSON("abc" << false << "b" << true ) ); // Date_t now = jsTime(); // keyTest( BSON("" << now << "" << 3 << "" << jstNULL << "" << true) ); // keyTest( BSON("" << now << "" << 3 << "" << BSONObj() << "" << true) ); //{ //{ //// check signed dates with new key format // KeyV1Owned a( BSONObjBuilder().appendDate("", -50).obj() ); // KeyV1Owned b( BSONObjBuilder().appendDate("", 50).obj() ); // ASSERT( a.woCompare(b, Ordering::make(BSONObj())) < 0 ); //} //{ //// backward compatibility // KeyBson a( BSONObjBuilder().appendDate("", -50).obj() ); // KeyBson b( BSONObjBuilder().appendDate("", 50).obj() ); // ASSERT( a.woCompare(b, Ordering::make(BSONObj())) > 0 ); //} //{ //// this is an uncompactable key: // BSONObj uc1 = BSONObjBuilder().appendDate("", -50).appendCode("", "abc").obj(); // BSONObj uc2 = BSONObjBuilder().appendDate("", 55).appendCode("", "abc").obj(); // ASSERT( uc1.woCompare(uc2, Ordering::make(BSONObj())) < 0 ); //{ // KeyV1Owned a(uc1); // KeyV1Owned b(uc2); // ASSERT( !a.isCompactFormat() ); // ASSERT( a.woCompare(b, Ordering::make(BSONObj())) < 0 ); //} //{ // KeyBson a(uc1); // KeyBson b(uc2); // ASSERT( !a.isCompactFormat() ); // ASSERT( a.woCompare(b, Ordering::make(BSONObj())) > 0 ); //} //} //} { BSONObjBuilder b; b.appendBinData("f", 8, (BinDataType)1, "aaaabbbb"); b.appendBinData("e", 3, (BinDataType)1, "aaa"); b.appendBinData("b", 1, (BinDataType)1, "x"); BSONObj o = b.obj(); // keyTest( o, true ); } { // check (non)equality BSONObj a = BSONObjBuilder().appendBinData("", 8, (BinDataType)1, "abcdefgh").obj(); BSONObj b = BSONObjBuilder().appendBinData("", 8, (BinDataType)1, "abcdefgj").obj(); ASSERT(!a.equal(b)); int res_ab = a.woCompare(b); ASSERT(res_ab != 0); // keyTest( a, true ); // keyTest( b, true ); // check subtypes do not equal BSONObj c = BSONObjBuilder().appendBinData("", 8, (BinDataType)4, "abcdefgh").obj(); BSONObj d = BSONObjBuilder().appendBinData("", 8, (BinDataType)0x81, "abcdefgh").obj(); ASSERT(!a.equal(c)); int res_ac = a.woCompare(c); ASSERT(res_ac != 0); // keyTest( c, true ); ASSERT(!a.equal(d)); int res_ad = a.woCompare(d); ASSERT(res_ad != 0); // keyTest( d, true ); // KeyV1Owned A(a); // KeyV1Owned B(b); // KeyV1Owned C(c); // KeyV1Owned D(d); // ASSERT( !A.woEqual(B) ); // ASSERT( A.woCompare(B, Ordering::make(BSONObj())) < 0 && res_ab < 0 ); // ASSERT( !A.woEqual(C) ); // ASSERT( A.woCompare(C, Ordering::make(BSONObj())) < 0 && res_ac < 0 ); // ASSERT( !A.woEqual(D) ); // ASSERT( A.woCompare(D, Ordering::make(BSONObj())) < 0 && res_ad < 0 ); } { BSONObjBuilder b; b.appendBinData("f", 33, (BinDataType)1, "123456789012345678901234567890123"); BSONObj o = b.obj(); // keyTest( o, false ); } { for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { BSONObjBuilder b; b.appendBinData("f", i, (BinDataType)j, "abc"); BSONObj o = b.obj(); // keyTest( o, j != ByteArrayDeprecated ); } } } { BSONObjBuilder b; b.appendBinData("f", 1, (BinDataType)133, "a"); // bsonobj o = b.obj(); // keyTest( o, true ); } { BSONObjBuilder b; b.append("AA", 3); b.appendBinData("f", 0, (BinDataType)0, ""); b.appendBinData("e", 3, (BinDataType)7, "aaa"); b.appendBinData("b", 1, (BinDataType)128, "x"); b.append("z", 3); b.appendBinData("bb", 0, (BinDataType)129, "x"); BSONObj o = b.obj(); // keyTest( o, true ); } { // 9 is not supported in compact format. so test a non-compact case here. BSONObjBuilder b; b.appendBinData("f", 9, (BinDataType)0, "aaaabbbbc"); BSONObj o = b.obj(); // keyTest( o ); } } }; DBTEST_SHIM_TEST(ToStringArray); class ToStringNumber { public: void run() { BSONObjBuilder b; b.append("a", (int)4); b.append("b", (double)5); b.append("c", (long long)6); b.append("d", 123.456789123456789123456789123456789); b.append("e", 123456789.123456789123456789123456789); b.append("f", 1234567891234567891234.56789123456789); b.append("g", -123.456); b.append("h", 0.0); b.append("i", -0.0); BSONObj x = b.obj(); // keyTest(x); ASSERT_EQUALS("4", x["a"].toString(false, true)); ASSERT_EQUALS("5.0", x["b"].toString(false, true)); ASSERT_EQUALS("6", x["c"].toString(false, true)); ASSERT_EQUALS("123.4567891234568", x["d"].toString(false, true)); ASSERT_EQUALS("123456789.1234568", x["e"].toString(false, true)); // ASSERT_EQUALS( "1.234567891234568e+21" , x["f"].toString( false , true ) ); // windows // and *nix are different - TODO, work around for test or not bother? ASSERT_EQUALS("-123.456", x["g"].toString(false, true)); ASSERT_EQUALS("0.0", x["h"].toString(false, true)); ASSERT_EQUALS("-0.0", x["i"].toString(false, true)); } }; DBTEST_SHIM_TEST(ToStringNumber); class NullString { public: void run() { { BSONObjBuilder b; const char x[] = {'a', 0, 'b', 0}; b.append("field", x, 4); b.append("z", true); BSONObj B = b.obj(); // cout << B.toString() << endl; BSONObjBuilder a; const char xx[] = {'a', 0, 'c', 0}; a.append("field", xx, 4); a.append("z", true); BSONObj A = a.obj(); BSONObjBuilder c; const char xxx[] = {'a', 0, 'c', 0, 0}; c.append("field", xxx, 5); c.append("z", true); BSONObj C = c.obj(); // test that nulls are ok within bson strings ASSERT(!(A == B)); ASSERT(A > B); ASSERT(!(B == C)); ASSERT(C > B); // check iteration is ok ASSERT(B["z"].Bool() && A["z"].Bool() && C["z"].Bool()); } BSONObjBuilder b; b.append("a", "a\0b", 4); string z("a\0b", 3); b.append("b", z); b.appendAs(b.asTempObj()["a"], "c"); BSONObj o = b.obj(); // keyTest(o); stringstream ss; ss << 'a' << '\0' << 'b'; ASSERT_EQUALS(o["a"].valuestrsize(), 3 + 1); ASSERT_EQUALS(o["a"].str(), ss.str()); ASSERT_EQUALS(o["b"].valuestrsize(), 3 + 1); ASSERT_EQUALS(o["b"].str(), ss.str()); ASSERT_EQUALS(o["c"].valuestrsize(), 3 + 1); ASSERT_EQUALS(o["c"].str(), ss.str()); } }; DBTEST_SHIM_TEST(NullString); class AppendAs { public: void run() { BSONObjBuilder b; { BSONObj foo = BSON("foo" << 1); b.appendAs(foo.firstElement(), "bar"); } ASSERT_EQUALS(BSON("bar" << 1), b.done()); } }; DBTEST_SHIM_TEST(AppendAs); class GetField { public: void run() { BSONObj o = BSON("a" << 1 << "b" << BSON("a" << 2) << "c" << BSON_ARRAY(BSON("a" << 3) << BSON("a" << 4))); ASSERT_EQUALS(1, o.getFieldDotted("a").numberInt()); ASSERT_EQUALS(2, o.getFieldDotted("b.a").numberInt()); ASSERT_EQUALS(3, o.getFieldDotted("c.0.a").numberInt()); ASSERT_EQUALS(4, o.getFieldDotted("c.1.a").numberInt()); ASSERT(o.getFieldDotted("x").eoo()); ASSERT(o.getFieldDotted("a.x").eoo()); ASSERT(o.getFieldDotted("x.y").eoo()); ASSERT(o.getFieldDotted("").eoo()); ASSERT(o.getFieldDotted(".").eoo()); ASSERT(o.getFieldDotted("..").eoo()); ASSERT(o.getFieldDotted("...").eoo()); ASSERT(o.getFieldDotted("a.").eoo()); ASSERT(o.getFieldDotted(".a").eoo()); ASSERT(o.getFieldDotted("b.a.").eoo()); // keyTest(o); } }; DBTEST_SHIM_TEST(GetField); class ToStringRecursionDepth { public: // create a nested BSON object with the specified recursion depth BSONObj recursiveBSON(int depth) { BSONObjBuilder b; if (depth == 0) { b << "name" << "Joe"; return b.obj(); } b.append("test", recursiveBSON(depth - 1)); return b.obj(); } void run() { BSONObj nestedBSON; StringBuilder s; string nestedBSONString; size_t found; // recursion depth one less than max allowed-- do not shorten the string nestedBSON = recursiveBSON(BSONObj::maxToStringRecursionDepth - 1); nestedBSON.toString(s, true, false); nestedBSONString = s.str(); found = nestedBSONString.find("..."); // did not find the "..." pattern ASSERT_EQUALS(found != string::npos, false); // recursion depth is equal to max allowed -- do not shorten the string nestedBSON = recursiveBSON(BSONObj::maxToStringRecursionDepth); nestedBSON.toString(s, true, false); nestedBSONString = s.str(); found = nestedBSONString.find("..."); // did not find the "..." pattern ASSERT_EQUALS(found != string::npos, false); // recursion depth - one greater than max allowed -- shorten the string nestedBSON = recursiveBSON(BSONObj::maxToStringRecursionDepth + 1); nestedBSON.toString(s, false, false); nestedBSONString = s.str(); found = nestedBSONString.find("..."); // found the "..." pattern ASSERT_EQUALS(found != string::npos, true); /* recursion depth - one greater than max allowed but with full=true * should fail with an assertion */ nestedBSON = recursiveBSON(BSONObj::maxToStringRecursionDepth + 1); ASSERT_THROWS(nestedBSON.toString(s, false, true), UserException); } }; DBTEST_SHIM_TEST(ToStringRecursionDepth); class StringWithNull { public: void run() { const string input = string("a") + '\0' + 'b'; ASSERT_EQUALS(input.size(), 3U); BSONObj obj = BSON("str" << input); const string output = obj.firstElement().String(); ASSERT_EQUALS(escape(output), escape(input)); // for better failure output ASSERT_EQUALS(output, input); } }; DBTEST_SHIM_TEST(StringWithNull); namespace Validation { class Base { public: virtual ~Base() {} void run() { ASSERT(valid().valid()); ASSERT(!invalid().valid()); } protected: virtual BSONObj valid() const { return BSONObj(); } virtual BSONObj invalid() const { return BSONObj(); } static char get(const BSONObj& o, int i) { return o.objdata()[i]; } static void set(BSONObj& o, int i, char c) { const_cast(o.objdata())[i] = c; } }; class BadType : public Base { BSONObj valid() const { return fromjson("{\"a\":1}"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, 4, 50); return ret; } }; DBTEST_SHIM_TEST(BadType); class EooBeforeEnd : public Base { BSONObj valid() const { return fromjson("{\"a\":1}"); } BSONObj invalid() const { BSONObj ret = valid(); // (first byte of size)++ set(ret, 0, get(ret, 0) + 1); // re-read size for BSONObj::details return ret.copy(); } }; DBTEST_SHIM_TEST(EooBeforeEnd); class Undefined : public Base { public: void run() { BSONObjBuilder b; b.appendNull("a"); BSONObj o = b.done(); set(o, 4, mongo::Undefined); ASSERT(o.valid()); } }; DBTEST_SHIM_TEST(Undefined); class TotalSizeTooSmall : public Base { BSONObj valid() const { return fromjson("{\"a\":1}"); } BSONObj invalid() const { BSONObj ret = valid(); // (first byte of size)-- set(ret, 0, get(ret, 0) - 1); // re-read size for BSONObj::details return ret.copy(); } }; DBTEST_SHIM_TEST(TotalSizeTooSmall); class EooMissing : public Base { BSONObj valid() const { return fromjson("{\"a\":1}"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, ret.objsize() - 1, (char)0xff); // (first byte of size)-- set(ret, 0, get(ret, 0) - 1); // re-read size for BSONObj::details return ret.copy(); } }; DBTEST_SHIM_TEST(EooMissing); class WrongStringSize : public Base { BSONObj valid() const { return fromjson("{\"a\":\"b\"}"); } BSONObj invalid() const { BSONObj ret = valid(); // This is essentialy testing the same thing as valid() above, // the real test is on the returned BSONObj with null set to 1 // ASSERT_EQUALS( ret.firstElement().valuestr()[0] , 'b' ); // ASSERT_EQUALS( ret.firstElement().valuestr()[1] , 0 ); ((char*)ret.firstElement().valuestr())[1] = 1; return ret.copy(); } }; DBTEST_SHIM_TEST(WrongStringSize); class ZeroStringSize : public Base { BSONObj valid() const { return fromjson("{\"a\":\"b\"}"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, 7, 0); return ret; } }; DBTEST_SHIM_TEST(ZeroStringSize); class NegativeStringSize : public Base { BSONObj valid() const { return fromjson("{\"a\":\"b\"}"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, 10, -100); return ret; } }; DBTEST_SHIM_TEST(NegativeStringSize); class WrongSubobjectSize : public Base { BSONObj valid() const { return fromjson("{\"a\":{\"b\":1}}"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, 0, get(ret, 0) + 1); set(ret, 7, get(ret, 7) + 1); return ret.copy(); } }; DBTEST_SHIM_TEST(WrongSubobjectSize); class WrongDbrefNsSize : public Base { BSONObj valid() const { return fromjson("{ \"a\": Dbref( \"b\", \"ffffffffffffffffffffffff\" ) }"); } BSONObj invalid() const { BSONObj ret = valid(); set(ret, 0, get(ret, 0) + 1); set(ret, 7, get(ret, 7) + 1); return ret.copy(); }; }; DBTEST_SHIM_TEST(WrongDbrefNsSize); class NoFieldNameEnd : public Base { BSONObj valid() const { return fromjson("{\"a\":1}"); } BSONObj invalid() const { BSONObj ret = valid(); memset(const_cast(ret.objdata()) + 5, 0xff, ret.objsize() - 5); return ret; } }; DBTEST_SHIM_TEST(NoFieldNameEnd); class BadRegex : public Base { BSONObj valid() const { return fromjson("{\"a\":/c/i}"); } BSONObj invalid() const { BSONObj ret = valid(); memset(const_cast(ret.objdata()) + 7, 0xff, ret.objsize() - 7); return ret; } }; DBTEST_SHIM_TEST(BadRegex); class BadRegexOptions : public Base { BSONObj valid() const { return fromjson("{\"a\":/c/i}"); } BSONObj invalid() const { BSONObj ret = valid(); memset(const_cast(ret.objdata()) + 9, 0xff, ret.objsize() - 9); return ret; } }; DBTEST_SHIM_TEST(BadRegexOptions); class CodeWScopeBase : public Base { BSONObj valid() const { BSONObjBuilder b; BSONObjBuilder scope; scope.append("a", "b"); b.appendCodeWScope("c", "d", scope.done()); return b.obj(); } BSONObj invalid() const { BSONObj ret = valid(); modify(ret); return ret; } protected: virtual void modify(BSONObj& o) const = 0; }; class CodeWScopeSmallSize : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 7, 7); } }; DBTEST_SHIM_TEST(CodeWScopeSmallSize); class CodeWScopeZeroStrSize : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 11, 0); } }; DBTEST_SHIM_TEST(CodeWScopeZeroStrSize); class CodeWScopeSmallStrSize : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 11, 1); } }; DBTEST_SHIM_TEST(CodeWScopeSmallStrSize); class CodeWScopeNoSizeForObj : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 7, 13); } }; DBTEST_SHIM_TEST(CodeWScopeNoSizeForObj); class CodeWScopeSmallObjSize : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 17, 1); } }; DBTEST_SHIM_TEST(CodeWScopeSmallObjSize); class CodeWScopeBadObject : public CodeWScopeBase { void modify(BSONObj& o) const { set(o, 21, JSTypeMax + 1); } }; DBTEST_SHIM_TEST(CodeWScopeBadObject); class NoSize { public: NoSize(BSONType type) : type_(type) {} void run() { const char data[] = {0x07, 0x00, 0x00, 0x00, char(type_), 'a', 0x00}; BSONObj o(data); ASSERT(!o.valid()); } private: BSONType type_; }; DBTEST_SHIM_TEST_NAMED(NoSize, Symbol, Symbol); DBTEST_SHIM_TEST_NAMED(NoSize, Code, Code); DBTEST_SHIM_TEST_NAMED(NoSize, String, String); DBTEST_SHIM_TEST_NAMED(NoSize, CodeWScope, CodeWScope); DBTEST_SHIM_TEST_NAMED(NoSize, DBRef, DBRef); DBTEST_SHIM_TEST_NAMED(NoSize, Object, Object); DBTEST_SHIM_TEST_NAMED(NoSize, Array, Array); DBTEST_SHIM_TEST_NAMED(NoSize, BinData, BinData); } // namespace Validation } // namespace BSONObjTests namespace OIDTests { class init1 { public: void run() { OID a; OID b; a.init(); b.init(); ASSERT(a != b); } }; DBTEST_SHIM_TEST(init1); class initParse1 { public: void run() { OID a; OID b; a.init(); b.init(a.toString()); ASSERT(a == b); } }; DBTEST_SHIM_TEST(initParse1); class append { public: void run() { BSONObjBuilder b; b.appendOID("a", 0); b.appendOID("b", 0, false); b.appendOID("c", 0, true); BSONObj o = b.obj(); // keyTest(o); ASSERT(o["a"].__oid().toString() == "000000000000000000000000"); ASSERT(o["b"].__oid().toString() == "000000000000000000000000"); ASSERT(o["c"].__oid().toString() != "000000000000000000000000"); } }; DBTEST_SHIM_TEST(append); class increasing { public: BSONObj g() { BSONObjBuilder b; b.appendOID("_id", 0, true); return b.obj(); } void run() { BSONObj a = g(); BSONObj b = g(); ASSERT(a.woCompare(b) < 0); // yes, there is a 1/1000 chance this won't increase time(0) // and therefore inaccurately say the function is behaving // buf if its broken, it will fail 999/1000, so i think that's good enough sleepsecs(1); BSONObj c = g(); ASSERT(a.woCompare(c) < 0); } }; DBTEST_SHIM_TEST(increasing); class ToDate { public: void run() { OID oid; const Date_t base(::time(0)); oid.init(base); ASSERT_EQUALS(base.millis / 1000, oid.asDateT().millis / 1000); ASSERT_EQUALS(base.toTimeT(), oid.asTimeT()); } }; DBTEST_SHIM_TEST(ToDate); class FromDate { public: void run() { OID min, oid, max; Date_t now = jsTime(); oid.init(); // slight chance this has different time. If its a problem, can change. min.init(now); max.init(now, true); ASSERT_EQUALS((unsigned)oid.asTimeT(), now / 1000); ASSERT_EQUALS((unsigned)min.asTimeT(), now / 1000); ASSERT_EQUALS((unsigned)max.asTimeT(), now / 1000); ASSERT(BSON("" << min).woCompare(BSON("" << oid)) < 0); ASSERT(BSON("" << max).woCompare(BSON("" << oid)) > 0); } }; DBTEST_SHIM_TEST(FromDate); } // namespace OIDTests namespace ValueStreamTests { class LabelBase { public: virtual ~LabelBase() {} void run() { ASSERT(!expected().woCompare(actual())); } protected: virtual BSONObj expected() = 0; virtual BSONObj actual() = 0; }; class LabelBasic : public LabelBase { BSONObj expected() { return BSON("a" << (BSON("$gt" << 1))); } BSONObj actual() { return BSON("a" << GT << 1); } }; DBTEST_SHIM_TEST(LabelBasic); class LabelShares : public LabelBase { BSONObj expected() { return BSON("z" << "q" << "a" << (BSON("$gt" << 1)) << "x" << "p"); } BSONObj actual() { return BSON("z" << "q" << "a" << GT << 1 << "x" << "p"); } }; DBTEST_SHIM_TEST(LabelShares); class LabelDouble : public LabelBase { BSONObj expected() { return BSON("a" << (BSON("$gt" << 1 << "$lte" << "x"))); } BSONObj actual() { return BSON("a" << GT << 1 << LTE << "x"); } }; DBTEST_SHIM_TEST(LabelDouble); class LabelDoubleShares : public LabelBase { BSONObj expected() { return BSON("z" << "q" << "a" << (BSON("$gt" << 1 << "$lte" << "x")) << "x" << "p"); } BSONObj actual() { return BSON("z" << "q" << "a" << GT << 1 << LTE << "x" << "x" << "p"); } }; DBTEST_SHIM_TEST(LabelDoubleShares); class LabelSize : public LabelBase { BSONObj expected() { return BSON("a" << BSON("$size" << 4)); } BSONObj actual() { return BSON("a" << mongo::BSIZE << 4); } }; DBTEST_SHIM_TEST(LabelSize); class LabelMulti : public LabelBase { BSONObj expected() { return BSON("z" << "q" << "a" << BSON("$gt" << 1 << "$lte" << "x") << "b" << BSON("$ne" << 1 << "$ne" << "f" << "$ne" << 22.3) << "x" << "p"); } BSONObj actual() { return BSON("z" << "q" << "a" << GT << 1 << LTE << "x" << "b" << NE << 1 << NE << "f" << NE << 22.3 << "x" << "p"); } }; DBTEST_SHIM_TEST(LabelMulti); class LabelishOr : public LabelBase { BSONObj expected() { return BSON("$or" << BSON_ARRAY(BSON("a" << BSON("$gt" << 1 << "$lte" << "x")) << BSON("b" << BSON("$ne" << 1 << "$ne" << "f" << "$ne" << 22.3)) << BSON("x" << "p"))); } BSONObj actual() { return OR(BSON("a" << GT << 1 << LTE << "x"), BSON("b" << NE << 1 << NE << "f" << NE << 22.3), BSON("x" << "p")); } }; DBTEST_SHIM_TEST(LabelishOr); class Unallowed { public: void run() { ASSERT_THROWS(BSON(GT << 4), MsgAssertionException); ASSERT_THROWS(BSON("a" << 1 << GT << 4), MsgAssertionException); } }; DBTEST_SHIM_TEST(Unallowed); class ElementAppend { public: void run() { BSONObj a = BSON("a" << 17); BSONObj b = BSON("b" << a["a"]); ASSERT_EQUALS(NumberInt, a["a"].type()); ASSERT_EQUALS(NumberInt, b["b"].type()); ASSERT_EQUALS(17, b["b"].number()); } }; DBTEST_SHIM_TEST(ElementAppend); class AllTypes { public: void run() { // These are listed in order of BSONType ASSERT_EQUALS(objTypeOf(MINKEY), MinKey); ASSERT_EQUALS(arrTypeOf(MINKEY), MinKey); // EOO not valid in middle of BSONObj ASSERT_EQUALS(objTypeOf(1.0), NumberDouble); ASSERT_EQUALS(arrTypeOf(1.0), NumberDouble); ASSERT_EQUALS(objTypeOf(""), String); ASSERT_EQUALS(arrTypeOf(""), String); ASSERT_EQUALS(objTypeOf(string()), String); ASSERT_EQUALS(arrTypeOf(string()), String); ASSERT_EQUALS(objTypeOf(StringData("")), String); ASSERT_EQUALS(arrTypeOf(StringData("")), String); ASSERT_EQUALS(objTypeOf(BSONObj()), Object); ASSERT_EQUALS(arrTypeOf(BSONObj()), Object); ASSERT_EQUALS(objTypeOf(BSONArray()), Array); ASSERT_EQUALS(arrTypeOf(BSONArray()), Array); ASSERT_EQUALS(objTypeOf(BSONBinData("", 0, BinDataGeneral)), BinData); ASSERT_EQUALS(arrTypeOf(BSONBinData("", 0, BinDataGeneral)), BinData); ASSERT_EQUALS(objTypeOf(BSONUndefined), Undefined); ASSERT_EQUALS(arrTypeOf(BSONUndefined), Undefined); ASSERT_EQUALS(objTypeOf(OID()), jstOID); ASSERT_EQUALS(arrTypeOf(OID()), jstOID); ASSERT_EQUALS(objTypeOf(true), Bool); ASSERT_EQUALS(arrTypeOf(true), Bool); ASSERT_EQUALS(objTypeOf(Date_t()), Date); ASSERT_EQUALS(arrTypeOf(Date_t()), Date); ASSERT_EQUALS(objTypeOf(BSONNULL), jstNULL); ASSERT_EQUALS(arrTypeOf(BSONNULL), jstNULL); ASSERT_EQUALS(objTypeOf(BSONRegEx("", "")), RegEx); ASSERT_EQUALS(arrTypeOf(BSONRegEx("", "")), RegEx); ASSERT_EQUALS(objTypeOf(BSONDBRef("", OID())), DBRef); ASSERT_EQUALS(arrTypeOf(BSONDBRef("", OID())), DBRef); ASSERT_EQUALS(objTypeOf(BSONCode("")), Code); ASSERT_EQUALS(arrTypeOf(BSONCode("")), Code); ASSERT_EQUALS(objTypeOf(BSONSymbol("")), Symbol); ASSERT_EQUALS(arrTypeOf(BSONSymbol("")), Symbol); ASSERT_EQUALS(objTypeOf(BSONCodeWScope("", BSONObj())), CodeWScope); ASSERT_EQUALS(arrTypeOf(BSONCodeWScope("", BSONObj())), CodeWScope); ASSERT_EQUALS(objTypeOf(1), NumberInt); ASSERT_EQUALS(arrTypeOf(1), NumberInt); ASSERT_EQUALS(objTypeOf(Timestamp_t()), Timestamp); ASSERT_EQUALS(arrTypeOf(Timestamp_t()), Timestamp); ASSERT_EQUALS(objTypeOf(1LL), NumberLong); ASSERT_EQUALS(arrTypeOf(1LL), NumberLong); ASSERT_EQUALS(objTypeOf(MAXKEY), MaxKey); ASSERT_EQUALS(arrTypeOf(MAXKEY), MaxKey); } template BSONType objTypeOf(const T& thing) { return BSON("" << thing).firstElement().type(); } template BSONType arrTypeOf(const T& thing) { return BSON_ARRAY(thing).firstElement().type(); } }; DBTEST_SHIM_TEST(AllTypes); } // namespace ValueStreamTests class SubObjectBuilder { public: void run() { BSONObjBuilder b1; b1.append("a", "bcd"); BSONObjBuilder b2(b1.subobjStart("foo")); b2.append("ggg", 44.0); b2.done(); b1.append("f", 10.0); BSONObj ret = b1.done(); ASSERT(ret.valid()); ASSERT(ret.woCompare(fromjson("{a:'bcd',foo:{ggg:44},f:10}")) == 0); } }; DBTEST_SHIM_TEST(SubObjectBuilder); class DateBuilder { public: void run() { BSONObj o = BSON("" << Date_t(1234567890)); ASSERT(o.firstElement().type() == Date); ASSERT(o.firstElement().date() == Date_t(1234567890)); } }; DBTEST_SHIM_TEST(DateBuilder); class DateNowBuilder { public: void run() { Date_t before = jsTime(); BSONObj o = BSON("now" << DATENOW); Date_t after = jsTime(); ASSERT(o.valid()); BSONElement e = o["now"]; ASSERT(e.type() == Date); ASSERT(e.date() >= before); ASSERT(e.date() <= after); } }; DBTEST_SHIM_TEST(DateNowBuilder); class TimeTBuilder { public: void run() { Date_t before = jsTime(); sleepmillis(2); time_t now = jsTime().toTimeT(); sleepmillis(2); Date_t after = jsTime(); BSONObjBuilder b; b.appendTimeT("now", now); BSONObj o = b.obj(); ASSERT(o.valid()); BSONElement e = o["now"]; ASSERT(e.type() == Date); ASSERT(e.date() / 1000 >= before / 1000); ASSERT(e.date() / 1000 <= after / 1000); } }; DBTEST_SHIM_TEST(TimeTBuilder); class MinMaxKeyBuilder { public: void run() { BSONObj min = BSON("a" << MINKEY); BSONObj max = BSON("b" << MAXKEY); ASSERT(min.valid()); ASSERT(max.valid()); BSONElement minElement = min["a"]; BSONElement maxElement = max["b"]; ASSERT(minElement.type() == MinKey); ASSERT(maxElement.type() == MaxKey); } }; DBTEST_SHIM_TEST(MinMaxKeyBuilder); class MinMaxElementTest { public: BSONObj min(int t) { BSONObjBuilder b; b.appendMinForType("a", t); return b.obj(); } BSONObj max(int t) { BSONObjBuilder b; b.appendMaxForType("a", t); return b.obj(); } void run() { for (int t = 1; t < JSTypeMax; t++) { stringstream ss; ss << "type: " << t; string s = ss.str(); ASSERT(min(t).woCompare(max(t)) <= 0); ASSERT(max(t).woCompare(min(t)) >= 0); ASSERT(min(t).woCompare(min(t)) == 0); ASSERT(max(t).woCompare(max(t)) == 0); } } }; DBTEST_SHIM_TEST(MinMaxElementTest); class ExtractFieldsTest { public: void run() { BSONObj x = BSON("a" << 10 << "b" << 11); verify(BSON("a" << 10).woCompare(x.extractFields(BSON("a" << 1))) == 0); verify(BSON("b" << 11).woCompare(x.extractFields(BSON("b" << 1))) == 0); verify(x.woCompare(x.extractFields(BSON("a" << 1 << "b" << 1))) == 0); verify((string) "a" == x.extractFields(BSON("a" << 1 << "c" << 1)).firstElementFieldName()); } }; DBTEST_SHIM_TEST(ExtractFieldsTest); class ComparatorTest { public: BSONObj one(string s) { return BSON("x" << s); } BSONObj two(string x, string y) { BSONObjBuilder b; b.append("x", x); if (y.size()) b.append("y", y); else b.appendNull("y"); return b.obj(); } void test(BSONObj order, BSONObj l, BSONObj r, bool wanted) { BSONObjCmp c(order); bool got = c(l, r); if (got == wanted) return; cout << " order: " << order << " l: " << l << "r: " << r << " wanted: " << wanted << " got: " << got << endl; } void lt(BSONObj order, BSONObj l, BSONObj r) { test(order, l, r, 1); } void run() { BSONObj s = BSON("x" << 1); BSONObj c = BSON("x" << 1 << "y" << 1); test(s, one("A"), one("B"), 1); test(s, one("B"), one("A"), 0); test(c, two("A", "A"), two("A", "B"), 1); test(c, two("A", "A"), two("B", "A"), 1); test(c, two("B", "A"), two("A", "B"), 0); lt(c, one("A"), two("A", "A")); lt(c, one("A"), one("B")); lt(c, two("A", ""), two("B", "A")); lt(c, two("B", "A"), two("C", "A")); lt(c, two("B", "A"), one("C")); lt(c, two("B", "A"), two("C", "")); } }; DBTEST_SHIM_TEST(ComparatorTest); class CompatBSON { public: #define JSONBSONTEST(j, s) ASSERT_EQUALS(fromjson(j).objsize(), s); #define RAWBSONTEST(j, s) ASSERT_EQUALS(j.objsize(), s); void run() { JSONBSONTEST("{ 'x' : true }", 9); JSONBSONTEST("{ 'x' : null }", 8); JSONBSONTEST("{ 'x' : 5.2 }", 16); JSONBSONTEST("{ 'x' : 'eliot' }", 18); JSONBSONTEST("{ 'x' : 5.2 , 'y' : 'truth' , 'z' : 1.1 }", 40); JSONBSONTEST("{ 'a' : { 'b' : 1.1 } }", 24); JSONBSONTEST("{ 'x' : 5.2 , 'y' : { 'a' : 'eliot' , b : true } , 'z' : null }", 44); JSONBSONTEST("{ 'x' : 5.2 , 'y' : [ 'a' , 'eliot' , 'b' , true ] , 'z' : null }", 62); RAWBSONTEST(BSON("x" << 4), 12); } }; DBTEST_SHIM_TEST(CompatBSON); class CompareDottedFieldNamesTest { public: void t(FieldCompareResult res, const string& l, const string& r) { LexNumCmp cmp(true); ASSERT_EQUALS(res, compareDottedFieldNames(l, r, cmp)); ASSERT_EQUALS(-1 * res, compareDottedFieldNames(r, l, cmp)); } void run() { t(SAME, "x", "x"); t(SAME, "x.a", "x.a"); t(SAME, "x.4", "x.4"); t(LEFT_BEFORE, "a", "b"); t(RIGHT_BEFORE, "b", "a"); t(LEFT_BEFORE, "x.04", "x.4"); t(LEFT_SUBFIELD, "a.x", "a"); t(LEFT_SUBFIELD, "a.4", "a"); } }; DBTEST_SHIM_TEST(CompareDottedFieldNamesTest); class CompareDottedArrayFieldNamesTest { public: void t(FieldCompareResult res, const string& l, const string& r) { LexNumCmp cmp(false); // Specify numeric comparison for array field names. ASSERT_EQUALS(res, compareDottedFieldNames(l, r, cmp)); ASSERT_EQUALS(-1 * res, compareDottedFieldNames(r, l, cmp)); } void run() { t(SAME, "0", "0"); t(SAME, "1", "1"); t(SAME, "0.1", "0.1"); t(SAME, "0.a", "0.a"); t(LEFT_BEFORE, "0", "1"); t(LEFT_BEFORE, "2", "10"); t(RIGHT_BEFORE, "1", "0"); t(RIGHT_BEFORE, "10", "2"); t(LEFT_SUBFIELD, "5.4", "5"); t(LEFT_SUBFIELD, "5.x", "5"); } }; DBTEST_SHIM_TEST(CompareDottedArrayFieldNamesTest); struct NestedDottedConversions { void t(const BSONObj& nest, const BSONObj& dot) { ASSERT_EQUALS(nested2dotted(nest), dot); ASSERT_EQUALS(nest, dotted2nested(dot)); } void run() { t(BSON("a" << BSON("b" << 1)), BSON("a.b" << 1)); t(BSON("a" << BSON("b" << 1 << "c" << 1)), BSON("a.b" << 1 << "a.c" << 1)); t(BSON("a" << BSON("b" << 1 << "c" << 1) << "d" << 1), BSON("a.b" << 1 << "a.c" << 1 << "d" << 1)); t(BSON("a" << BSON("b" << 1 << "c" << 1 << "e" << BSON("f" << 1)) << "d" << 1), BSON("a.b" << 1 << "a.c" << 1 << "a.e.f" << 1 << "d" << 1)); } }; DBTEST_SHIM_TEST(NestedDottedConversions); struct BSONArrayBuilderTest { void run() { int i = 0; BSONObjBuilder objb; BSONArrayBuilder arrb; objb << objb.numStr(i++) << 100; arrb << 100; objb << objb.numStr(i++) << 1.0; arrb << 1.0; objb << objb.numStr(i++) << "Hello"; arrb << "Hello"; objb << objb.numStr(i++) << string("World"); arrb << string("World"); objb << objb.numStr(i++) << BSON("a" << 1 << "b" << "foo"); arrb << BSON("a" << 1 << "b" << "foo"); objb << objb.numStr(i++) << BSON("a" << 1)["a"]; arrb << BSON("a" << 1)["a"]; OID oid; oid.init(); objb << objb.numStr(i++) << oid; arrb << oid; objb.appendUndefined(objb.numStr(i++)); arrb.appendUndefined(); objb.appendRegex(objb.numStr(i++), "test", "imx"); arrb.appendRegex("test", "imx"); objb.appendBinData(objb.numStr(i++), 4, BinDataGeneral, "wow"); arrb.appendBinData(4, BinDataGeneral, "wow"); objb.appendCode(objb.numStr(i++), "function(){ return 1; }"); arrb.appendCode("function(){ return 1; }"); objb.appendCodeWScope(objb.numStr(i++), "function(){ return a; }", BSON("a" << 1)); arrb.appendCodeWScope("function(){ return a; }", BSON("a" << 1)); time_t dt(0); objb.appendTimeT(objb.numStr(i++), dt); arrb.appendTimeT(dt); Date_t date(0); objb.appendDate(objb.numStr(i++), date); arrb.appendDate(date); objb.append(objb.numStr(i++), BSONRegEx("test2", "s")); arrb.append(BSONRegEx("test2", "s")); BSONObj obj = objb.obj(); BSONArray arr = arrb.arr(); ASSERT_EQUALS(obj, arr); BSONObj o = BSON("obj" << obj << "arr" << arr << "arr2" << BSONArray(obj) << "regex" << BSONRegEx("reg", "x")); // keyTest(o); ASSERT_EQUALS(o["obj"].type(), Object); ASSERT_EQUALS(o["arr"].type(), Array); ASSERT_EQUALS(o["arr2"].type(), Array); ASSERT_EQUALS(o["regex"].type(), RegEx); } }; DBTEST_SHIM_TEST(BSONArrayBuilderTest); struct ArrayMacroTest { void run() { BSONArray arr = BSON_ARRAY("hello" << 1 << BSON("foo" << BSON_ARRAY("bar" << "baz" << "qux"))); BSONObj obj = BSON("0" << "hello" << "1" << 1 << "2" << BSON("foo" << BSON_ARRAY("bar" << "baz" << "qux"))); ASSERT_EQUALS(arr, obj); ASSERT_EQUALS(arr["2"].type(), Object); ASSERT_EQUALS(arr["2"].embeddedObject()["foo"].type(), Array); } }; DBTEST_SHIM_TEST(ArrayMacroTest); class NumberParsing { public: void run() { BSONObjBuilder a; BSONObjBuilder b; a.append("a", (int)1); ASSERT(b.appendAsNumber("a", "1")); a.append("b", 1.1); ASSERT(b.appendAsNumber("b", "1.1")); a.append("c", (int)-1); ASSERT(b.appendAsNumber("c", "-1")); a.append("d", -1.1); ASSERT(b.appendAsNumber("d", "-1.1")); a.append("e", (long long)32131231231232313LL); ASSERT(b.appendAsNumber("e", "32131231231232313")); ASSERT(!b.appendAsNumber("f", "zz")); ASSERT(!b.appendAsNumber("f", "5zz")); ASSERT(!b.appendAsNumber("f", "zz5")); ASSERT_EQUALS(a.obj(), b.obj()); } }; DBTEST_SHIM_TEST(NumberParsing); class bson2settest { public: void run() { BSONObj o = BSON("z" << 1 << "a" << 2 << "m" << 3 << "c" << 4); BSONObjIteratorSorted i(o); stringstream ss; while (i.more()) ss << i.next().fieldName(); ASSERT_EQUALS("acmz", ss.str()); { // Timer t; for (int i = 0; i < 10000; i++) { BSONObjIteratorSorted j(o); int l = 0; while (j.more()) l += strlen(j.next().fieldName()); } // unsigned long long tm = t.micros(); // cout << "time: " << tm << endl; } BSONObj o2 = BSON("2" << "a" << "11" << "b"); BSONObjIteratorSorted i2(o2); // First field in sorted order should be "11" due use of a lexical comparison. ASSERT_EQUALS("11", string(i2.next().fieldName())); } }; DBTEST_SHIM_TEST(bson2settest); class BSONArrayIteratorSorted { public: void run() { BSONArrayBuilder bab; for (int i = 0; i < 11; ++i) { bab << "a"; } BSONArray arr = bab.arr(); // The sorted iterator should perform numeric comparisons and return results in the same // order as the unsorted iterator. BSONObjIterator unsorted(arr); mongo::BSONArrayIteratorSorted sorted(arr); while (unsorted.more()) { ASSERT(sorted.more()); ASSERT_EQUALS(string(unsorted.next().fieldName()), sorted.next().fieldName()); } ASSERT(!sorted.more()); } }; DBTEST_SHIM_TEST(BSONArrayIteratorSorted); class checkForStorageTests { public: void good(string s) { good(fromjson(s)); } void good(BSONObj o) { if (o.okForStorageAsRoot()) return; throw UserException(12528, (string) "should be ok for storage:" + o.toString()); } void bad(string s) { bad(fromjson(s)); } void bad(BSONObj o) { if (!o.okForStorageAsRoot()) return; throw UserException(12529, (string) "should NOT be ok for storage:" + o.toString()); } void run() { // basic docs are good good("{}"); good("{x:1}"); good("{x:{a:2}}"); // no dots allowed bad("{'x.y':1}"); bad("{'x\\.y':1}"); // Check for $ bad("{x:{'$a':2}}"); good("{'a$b':2}"); good("{'a$': {b: 2}}"); good("{'a$':2}"); good("{'a $ a': 'foo'}"); // Queries are not ok bad("{num: {$gt: 1}}"); bad("{_id: {$regex:'test'}}"); bad("{$gt: 2}"); bad("{a : { oo: [ {$bad:1}, {good:1}] }}"); good("{a : { oo: [ {'\\\\$good':1}, {good:1}] }}"); // DBRef stuff -- json parser can't handle this yet good(BSON("a" << BSON("$ref" << "coll" << "$id" << 1))); good(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" << "a"))); good(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "stuff" << 1))); good(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" << "a" << "stuff" << 1))); bad(BSON("a" << BSON("$ref" << 1 << "$id" << 1))); bad(BSON("a" << BSON("$ref" << 1 << "$id" << 1 << "$db" << "a"))); bad(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" << 1))); bad(BSON("a" << BSON("$ref" << "coll"))); bad(BSON("a" << BSON("$ref" << "coll" << "$db" << "db"))); bad(BSON("a" << BSON("$id" << 1))); bad(BSON("a" << BSON("$id" << 1 << "$ref" << "coll"))); bad(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$hater" << 1))); bad(BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "dot.dot" << 1))); // _id isn't a RegEx, or Array good("{_id: 0}"); good("{_id: {a:1, b:1}}"); good("{_id: {rx: /a/}}"); good("{_id: {rx: {$regex: 'a'}}}"); bad("{_id: /a/ }"); bad("{_id: /a/, other:1}"); bad("{hi:1, _id: /a/ }"); bad("{_id: /a/i }"); bad("{first:/f/i, _id: /a/i }"); // Not really a regex type bad("{_id: {$regex: 'a'} }"); bad("{_id: {$regex: 'a', $options:'i'} }"); bad("{_id: [1,2]}"); bad("{_id: [1]}"); } }; DBTEST_SHIM_TEST(checkForStorageTests); class InvalidIDFind { public: void run() { BSONObj x = BSON("_id" << 5 << "t" << 2); { char* crap = (char*)malloc(x.objsize()); memcpy(crap, x.objdata(), x.objsize()); BSONObj y(crap); ASSERT_EQUALS(x, y); free(crap); } { char* crap = (char*)malloc(x.objsize()); memcpy(crap, x.objdata(), x.objsize()); int* foo = (int*)crap; foo[0] = 123123123; int state = 0; try { BSONObj y(crap); state = 1; } catch (std::exception& e) { state = 2; ASSERT(strstr(e.what(), "_id: 5") != NULL); } free(crap); ASSERT_EQUALS(2, state); } } }; DBTEST_SHIM_TEST(InvalidIDFind); class ElementSetTest { public: void run() { BSONObj x = BSON("a" << 1 << "b" << 1 << "c" << 2); BSONElement a = x["a"]; BSONElement b = x["b"]; BSONElement c = x["c"]; // cout << "c: " << c << endl; ASSERT(a.woCompare(b) != 0); ASSERT(a.woCompare(b, false) == 0); BSONElementSet s; s.insert(a); ASSERT_EQUALS(1U, s.size()); s.insert(b); ASSERT_EQUALS(1U, s.size()); ASSERT(!s.count(c)); ASSERT(s.find(a) != s.end()); ASSERT(s.find(b) != s.end()); ASSERT(s.find(c) == s.end()); s.insert(c); ASSERT_EQUALS(2U, s.size()); ASSERT(s.find(a) != s.end()); ASSERT(s.find(b) != s.end()); ASSERT(s.find(c) != s.end()); ASSERT(s.count(a)); ASSERT(s.count(b)); ASSERT(s.count(c)); { BSONElementSet x; BSONObj o = fromjson("{ 'a' : [ 1 , 2 , 1 ] }"); BSONObjIterator i(o["a"].embeddedObjectUserCheck()); while (i.more()) { x.insert(i.next()); } ASSERT_EQUALS(2U, x.size()); } } }; DBTEST_SHIM_TEST(ElementSetTest); class EmbeddedNumbers { public: void run() { BSONObj x = BSON("a" << BSON("b" << 1)); BSONObj y = BSON("a" << BSON("b" << 1.0)); // keyTest(x); keyTest(y); ASSERT_EQUALS(x, y); ASSERT_EQUALS(0, x.woCompare(y)); } }; DBTEST_SHIM_TEST(EmbeddedNumbers); class BuilderPartialItearte { public: void run() { { BSONObjBuilder b; b.append("x", 1); b.append("y", 2); BSONObjIterator i = b.iterator(); ASSERT(i.more()); ASSERT_EQUALS(1, i.next().numberInt()); ASSERT(i.more()); ASSERT_EQUALS(2, i.next().numberInt()); ASSERT(!i.more()); b.append("z", 3); i = b.iterator(); ASSERT(i.more()); ASSERT_EQUALS(1, i.next().numberInt()); ASSERT(i.more()); ASSERT_EQUALS(2, i.next().numberInt()); ASSERT(i.more()); ASSERT_EQUALS(3, i.next().numberInt()); ASSERT(!i.more()); ASSERT_EQUALS(BSON("x" << 1 << "y" << 2 << "z" << 3), b.obj()); } } }; DBTEST_SHIM_TEST(BuilderPartialItearte); class BSONForEachTest { public: void run() { BSONObj obj = BSON("a" << 1 << "a" << 2 << "a" << 3); int count = 0; BSONForEach(e, obj) { ASSERT_EQUALS(e.fieldName(), string("a")); count += e.Int(); } ASSERT_EQUALS(count, 1 + 2 + 3); } }; DBTEST_SHIM_TEST(BSONForEachTest); class CompareOps { public: void run() { BSONObj a = BSON("a" << 1); BSONObj b = BSON("a" << 1); BSONObj c = BSON("a" << 2); BSONObj d = BSON("a" << 3); BSONObj e = BSON("a" << 4); BSONObj f = BSON("a" << 4); ASSERT(!(a < b)); ASSERT(a <= b); ASSERT(a < c); ASSERT(f > d); ASSERT(f >= e); ASSERT(!(f > e)); } }; DBTEST_SHIM_TEST(CompareOps); class NestedBuilderOversize { public: void run() { try { BSONObjBuilder outer; BSONObjBuilder inner(outer.subobjStart("inner")); string bigStr(1000, 'x'); while (true) { ASSERT_LESS_THAN_OR_EQUALS(inner.len(), BufferMaxSize); inner.append("", bigStr); } ASSERT(!"Expected Throw"); } catch (const DBException& e) { if (e.getCode() != 13548) // we expect the code for oversized buffer throw; } } }; DBTEST_SHIM_TEST(NestedBuilderOversize); } // namespace JsobjTests mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/jsontests.cpp000066400000000000000000002235531273231111400243100ustar00rootroot00000000000000// jsontests.cpp - Tests for json.{h,cpp} code and BSONObj::jsonString() // /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" namespace JsonTests { using namespace std; namespace JsonStringTests { class Empty { public: void run() { ASSERT_EQUALS("{}", BSONObj().jsonString(Strict)); } }; DBTEST_SHIM_TEST(Empty); class SingleStringMember { public: void run() { ASSERT_EQUALS("{ \"a\" : \"b\" }", BSON("a" << "b").jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleStringMember); class EscapedCharacters { public: void run() { BSONObjBuilder b; b.append("a", "\" \\ / \b \f \n \r \t"); ASSERT_EQUALS("{ \"a\" : \"\\\" \\\\ / \\b \\f \\n \\r \\t\" }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(EscapedCharacters); // per http://www.ietf.org/rfc/rfc4627.txt, control characters are // (U+0000 through U+001F). U+007F is not mentioned as a control character. class AdditionalControlCharacters { public: void run() { BSONObjBuilder b; b.append("a", "\x1 \x1f"); ASSERT_EQUALS("{ \"a\" : \"\\u0001 \\u001f\" }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(AdditionalControlCharacters); class ExtendedAscii { public: void run() { BSONObjBuilder b; b.append("a", "\x80"); ASSERT_EQUALS("{ \"a\" : \"\x80\" }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(ExtendedAscii); class EscapeFieldName { public: void run() { BSONObjBuilder b; b.append("\t", "b"); ASSERT_EQUALS("{ \"\\t\" : \"b\" }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(EscapeFieldName); class SingleIntMember { public: void run() { BSONObjBuilder b; b.append("a", 1); ASSERT_EQUALS("{ \"a\" : 1 }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleIntMember); class SingleNumberMember { public: void run() { BSONObjBuilder b; b.append("a", 1.5); ASSERT_EQUALS("{ \"a\" : 1.5 }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleNumberMember); class InvalidNumbers { public: void run() { BSONObjBuilder c; c.append("a", numeric_limits::quiet_NaN()); string s = c.done().jsonString(Strict); // Note there is no NaN in the JSON RFC but what would be the alternative? ASSERT(str::contains(s, "NaN")); // commented out assertion as it doesn't throw anymore: // ASSERT_THROWS( c.done().jsonString( Strict ), AssertionException ); BSONObjBuilder d; d.append("a", numeric_limits::signaling_NaN()); // ASSERT_THROWS( d.done().jsonString( Strict ), AssertionException ); s = d.done().jsonString(Strict); ASSERT(str::contains(s, "NaN")); } }; DBTEST_SHIM_TEST(InvalidNumbers); class NumberPrecision { public: void run() { BSONObjBuilder b; b.append("a", 123456789); ASSERT_EQUALS("{ \"a\" : 123456789 }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberPrecision); class NegativeNumber { public: void run() { BSONObjBuilder b; b.append("a", -1); ASSERT_EQUALS("{ \"a\" : -1 }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NegativeNumber); class NumberLongStrict { public: void run() { BSONObjBuilder b; b.append("a", 20000LL); ASSERT_EQUALS("{ \"a\" : { \"$numberLong\" : \"20000\" } }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberLongStrict); // Test a NumberLong that is too big to fit into a 32 bit integer class NumberLongStrictLarge { public: void run() { BSONObjBuilder b; b.append("a", 9223372036854775807LL); ASSERT_EQUALS("{ \"a\" : { \"$numberLong\" : \"9223372036854775807\" } }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberLongStrictLarge); class NumberLongStrictNegative { public: void run() { BSONObjBuilder b; b.append("a", -20000LL); ASSERT_EQUALS("{ \"a\" : { \"$numberLong\" : \"-20000\" } }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberLongStrictNegative); class NumberDoubleNaN { public: void run() { BSONObjBuilder b; b.append("a", std::numeric_limits::quiet_NaN()); ASSERT_EQUALS("{ \"a\" : NaN }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberDoubleNaN); class NumberDoubleInfinity { public: void run() { BSONObjBuilder b; b.append("a", std::numeric_limits::infinity()); ASSERT_EQUALS("{ \"a\" : Infinity }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberDoubleInfinity); class NumberDoubleNegativeInfinity { public: void run() { BSONObjBuilder b; b.append("a", -std::numeric_limits::infinity()); ASSERT_EQUALS("{ \"a\" : -Infinity }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(NumberDoubleNegativeInfinity); class SingleBoolMember { public: void run() { BSONObjBuilder b; b.appendBool("a", true); ASSERT_EQUALS("{ \"a\" : true }", b.done().jsonString(Strict)); BSONObjBuilder c; c.appendBool("a", false); ASSERT_EQUALS("{ \"a\" : false }", c.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleBoolMember); class SingleNullMember { public: void run() { BSONObjBuilder b; b.appendNull("a"); ASSERT_EQUALS("{ \"a\" : null }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleNullMember); class SingleUndefinedMember { public: void run() { BSONObjBuilder b; b.appendUndefined("a"); ASSERT_EQUALS("{ \"a\" : { \"$undefined\" : true } }", b.done().jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : undefined }", b.done().jsonString(JS)); ASSERT_EQUALS("{ \"a\" : undefined }", b.done().jsonString(TenGen)); } }; DBTEST_SHIM_TEST(SingleUndefinedMember); class SingleObjectMember { public: void run() { BSONObjBuilder b, c; b.append("a", c.done()); ASSERT_EQUALS("{ \"a\" : {} }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(SingleObjectMember); class TwoMembers { public: void run() { BSONObjBuilder b; b.append("a", 1); b.append("b", 2); ASSERT_EQUALS("{ \"a\" : 1, \"b\" : 2 }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(TwoMembers); class EmptyArray { public: void run() { vector arr; BSONObjBuilder b; b.append("a", arr); ASSERT_EQUALS("{ \"a\" : [] }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(EmptyArray); class Array { public: void run() { vector arr; arr.push_back(1); arr.push_back(2); BSONObjBuilder b; b.append("a", arr); ASSERT_EQUALS("{ \"a\" : [ 1, 2 ] }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(Array); class DBRef { public: void run() { char OIDbytes[OID::kOIDSize]; memset(&OIDbytes, 0xff, OID::kOIDSize); OID oid = OID::from(OIDbytes); BSONObjBuilder b; b.appendDBRef("a", "namespace", oid); BSONObj built = b.done(); ASSERT_EQUALS( "{ \"a\" : { \"$ref\" : \"namespace\", \"$id\" : \"ffffffffffffffffffffffff\" } }", built.jsonString(Strict)); ASSERT_EQUALS( "{ \"a\" : { \"$ref\" : \"namespace\", \"$id\" : \"ffffffffffffffffffffffff\" } }", built.jsonString(JS)); ASSERT_EQUALS("{ \"a\" : Dbref( \"namespace\", \"ffffffffffffffffffffffff\" ) }", built.jsonString(TenGen)); } }; DBTEST_SHIM_TEST(DBRef); class DBRefZero { public: void run() { char OIDbytes[OID::kOIDSize]; memset(&OIDbytes, 0, OID::kOIDSize); OID oid = OID::from(OIDbytes); BSONObjBuilder b; b.appendDBRef("a", "namespace", oid); ASSERT_EQUALS( "{ \"a\" : { \"$ref\" : \"namespace\", \"$id\" : \"000000000000000000000000\" } }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(DBRefZero); class ObjectId { public: void run() { char OIDbytes[OID::kOIDSize]; memset(&OIDbytes, 0xff, OID::kOIDSize); OID oid = OID::from(OIDbytes); BSONObjBuilder b; b.appendOID("a", &oid); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$oid\" : \"ffffffffffffffffffffffff\" } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : ObjectId( \"ffffffffffffffffffffffff\" ) }", built.jsonString(TenGen)); } }; DBTEST_SHIM_TEST(ObjectId); class BinData { public: void run() { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, BinDataGeneral, z); string o = b.done().jsonString(Strict); ASSERT_EQUALS("{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"00\" } }", o); BSONObjBuilder c; c.appendBinData("a", 2, BinDataGeneral, z); ASSERT_EQUALS("{ \"a\" : { \"$binary\" : \"YWI=\", \"$type\" : \"00\" } }", c.done().jsonString(Strict)); BSONObjBuilder d; d.appendBinData("a", 1, BinDataGeneral, z); ASSERT_EQUALS("{ \"a\" : { \"$binary\" : \"YQ==\", \"$type\" : \"00\" } }", d.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(BinData); class Symbol { public: void run() { BSONObjBuilder b; b.appendSymbol("a", "b"); ASSERT_EQUALS("{ \"a\" : \"b\" }", b.done().jsonString(Strict)); } }; DBTEST_SHIM_TEST(Symbol); #ifdef _WIN32 char tzEnvString[] = "TZ=EST+5EDT"; #else char tzEnvString[] = "TZ=America/New_York"; #endif class Date { public: Date() { char* _oldTimezonePtr = getenv("TZ"); _oldTimezone = std::string(_oldTimezonePtr ? _oldTimezonePtr : ""); if (-1 == putenv(tzEnvString)) { // FAIL() << errnoWithDescription(); } tzset(); } ~Date() { if (!_oldTimezone.empty()) { #ifdef _WIN32 errno_t ret = _putenv_s("TZ", _oldTimezone.c_str()); if (0 != ret) { StringBuilder sb; sb << "Error setting TZ environment variable to: " << _oldTimezone << ". Error code: " << ret; // FAIL() << sb.str(); } #else if (-1 == setenv("TZ", _oldTimezone.c_str(), 1)) { // FAIL() << errnoWithDescription(); } #endif } else { #ifdef _WIN32 errno_t ret = _putenv_s("TZ", ""); if (0 != ret) { StringBuilder sb; sb << "Error unsetting TZ environment variable. Error code: " << ret; // FAIL() << sb.str(); } #else if (-1 == unsetenv("TZ")) { // FAIL() << errnoWithDescription(); } #endif } tzset(); } void run() { BSONObjBuilder b; b.appendDate("a", 0); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$date\" : \"1969-12-31T19:00:00.000-0500\" } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : Date( 0 ) }", built.jsonString(TenGen)); ASSERT_EQUALS("{ \"a\" : Date( 0 ) }", built.jsonString(JS)); // Test dates above our maximum formattable date. See SERVER-13760. BSONObjBuilder b2; b2.appendDate("a", 32535262800000ULL); BSONObj built2 = b2.done(); ASSERT_EQUALS("{ \"a\" : { \"$date\" : { \"$numberLong\" : \"32535262800000\" } } }", built2.jsonString(Strict)); } private: std::string _oldTimezone; }; DBTEST_SHIM_TEST(Date); class DateNegative { public: void run() { BSONObjBuilder b; b.appendDate("a", -1); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$date\" : { \"$numberLong\" : \"-1\" } } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : Date( -1 ) }", built.jsonString(TenGen)); ASSERT_EQUALS("{ \"a\" : Date( -1 ) }", built.jsonString(JS)); } }; DBTEST_SHIM_TEST(DateNegative); class Regex { public: void run() { BSONObjBuilder b; b.appendRegex("a", "abc", "i"); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$regex\" : \"abc\", \"$options\" : \"i\" } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : /abc/i }", built.jsonString(TenGen)); ASSERT_EQUALS("{ \"a\" : /abc/i }", built.jsonString(JS)); } }; DBTEST_SHIM_TEST(Regex); class RegexEscape { public: void run() { BSONObjBuilder b; b.appendRegex("a", "/\"", "i"); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$regex\" : \"/\\\"\", \"$options\" : \"i\" } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : /\\/\\\"/i }", built.jsonString(TenGen)); ASSERT_EQUALS("{ \"a\" : /\\/\\\"/i }", built.jsonString(JS)); } }; DBTEST_SHIM_TEST(RegexEscape); class RegexManyOptions { public: void run() { BSONObjBuilder b; b.appendRegex("a", "z", "abcgimx"); BSONObj built = b.done(); ASSERT_EQUALS("{ \"a\" : { \"$regex\" : \"z\", \"$options\" : \"abcgimx\" } }", built.jsonString(Strict)); ASSERT_EQUALS("{ \"a\" : /z/gim }", built.jsonString(TenGen)); ASSERT_EQUALS("{ \"a\" : /z/gim }", built.jsonString(JS)); } }; DBTEST_SHIM_TEST(RegexManyOptions); class CodeTests { public: void run() { BSONObjBuilder b; b.appendCode("x", "function(arg){ var string = \"\\n\"; return 1; }"); BSONObj o = b.obj(); ASSERT_EQUALS( "{ \"x\" : \"function(arg){ var string = \\\"\\\\n\\\"; " "return 1; }\" }", o.jsonString()); } }; DBTEST_SHIM_TEST(CodeTests); class CodeWScopeTests { public: void run() { BSONObjBuilder b; b.appendCodeWScope("x", "function(arg){ var string = \"\\n\"; return x; }", BSON("x" << 1)); BSONObj o = b.obj(); ASSERT_EQUALS( "{ \"x\" : " "{ \"$code\" : " "\"function(arg){ var string = \\\"\\\\n\\\"; return x; }\" , " "\"$scope\" : { \"x\" : 1 } } }", o.jsonString()); } }; DBTEST_SHIM_TEST(CodeWScopeTests); class TimestampTests { public: void run() { BSONObjBuilder b; b.appendTimestamp("x", Timestamp_t(4, 10)); BSONObj o = b.obj(); ASSERT_EQUALS("{ \"x\" : { \"$timestamp\" : { \"t\" : 4, \"i\" : 10 } } }", o.jsonString(Strict)); ASSERT_EQUALS("{ \"x\" : { \"$timestamp\" : { \"t\" : 4, \"i\" : 10 } } }", o.jsonString(JS)); ASSERT_EQUALS("{ \"x\" : Timestamp( 4, 10 ) }", o.jsonString(TenGen)); } }; DBTEST_SHIM_TEST(TimestampTests); class NullString { public: void run() { BSONObjBuilder b; b.append("x", "a\0b", 4); BSONObj o = b.obj(); ASSERT_EQUALS("{ \"x\" : \"a\\u0000b\" }", o.jsonString()); } }; DBTEST_SHIM_TEST(NullString); class AllTypes { public: void run() { OID oid; oid.init(); BSONObjBuilder b; b.appendMinKey("a"); b.append("b", 5.5); b.append("c", "abc"); b.append("e", BSON("x" << 1)); b.append("f", BSON_ARRAY(1 << 2 << 3)); b.appendBinData("g", sizeof(AllTypes), bdtCustom, (const void*)this); b.appendUndefined("h"); b.append("i", oid); b.appendBool("j", 1); b.appendDate("k", 123); b.appendNull("l"); b.appendRegex("m", "a"); b.appendDBRef("n", "foo", oid); b.appendCode("o", "function(){}"); b.appendSymbol("p", "foo"); b.appendCodeWScope("q", "function(){}", BSON("x" << 1)); b.append("r", (int)5); b.appendTimestamp("s", Timestamp_t(123123, 123123)); b.append("t", 12321312312LL); b.appendMaxKey("u"); BSONObj o = b.obj(); o.jsonString(); // cout << o.jsonString() << endl; } }; DBTEST_SHIM_TEST(AllTypes); } // namespace JsonStringTests namespace FromJsonTests { class Base { public: virtual ~Base() {} void run() { ASSERT(fromjson(json()).valid()); assertEquals(bson(), fromjson(tojson(bson())), "mode: "); assertEquals(bson(), fromjson(tojson(bson(), Strict)), "mode: strict"); assertEquals(bson(), fromjson(tojson(bson(), TenGen)), "mode: tengen"); assertEquals(bson(), fromjson(tojson(bson(), JS)), "mode: js"); } protected: virtual BSONObj bson() const = 0; virtual string json() const = 0; private: void assertEquals(const BSONObj& expected, const BSONObj& actual, const char* msg) { const bool bad = expected.woCompare(actual); if (bad) { ::mongo::log() << "want:" << expected.jsonString() << " size: " << expected.objsize() << endl; ::mongo::log() << "got :" << actual.jsonString() << " size: " << actual.objsize() << endl; ::mongo::log() << expected.hexDump() << endl; ::mongo::log() << actual.hexDump() << endl; ::mongo::log() << msg << endl; ::mongo::log() << "orig json:" << this->json(); } ASSERT(!bad); } }; class Bad { public: virtual ~Bad() {} void run() { ASSERT_THROWS(fromjson(json()), MsgAssertionException); } protected: virtual string json() const = 0; }; class Empty : public Base { virtual BSONObj bson() const { BSONObjBuilder b; return b.obj(); } virtual string json() const { return "{}"; } }; DBTEST_SHIM_TEST(Empty); class EmptyWithSpace : public Base { virtual BSONObj bson() const { BSONObjBuilder b; return b.obj(); } virtual string json() const { return "{ }"; } }; DBTEST_SHIM_TEST(EmptyWithSpace); class SingleString : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", "b"); return b.obj(); } virtual string json() const { return "{ \"a\" : \"b\" }"; } }; DBTEST_SHIM_TEST(SingleString); class EmptyStrings : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("", ""); return b.obj(); } virtual string json() const { return "{ \"\" : \"\" }"; } }; DBTEST_SHIM_TEST(EmptyStrings); class ReservedFieldName : public Bad { virtual string json() const { return "{ \"$oid\" : \"b\" }"; } }; DBTEST_SHIM_TEST(ReservedFieldName); class ReservedFieldName1 : public Bad { virtual string json() const { return "{ \"$ref\" : \"b\" }"; } }; DBTEST_SHIM_TEST(ReservedFieldName1); class NumberFieldName : public Bad { virtual string json() const { return "{ 0 : \"b\" }"; } }; DBTEST_SHIM_TEST(NumberFieldName); class InvalidFieldName : public Bad { virtual string json() const { return "{ test.test : \"b\" }"; } }; DBTEST_SHIM_TEST(InvalidFieldName); class QuotedNullName : public Bad { virtual string json() const { return "{ \"nc\0nc\" : \"b\" }"; } }; DBTEST_SHIM_TEST(QuotedNullName); class NoValue : public Bad { virtual string json() const { return "{ a : }"; } }; DBTEST_SHIM_TEST(NoValue); class InvalidValue : public Bad { virtual string json() const { return "{ a : a }"; } }; DBTEST_SHIM_TEST(InvalidValue); class OkDollarFieldName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("$where", 1); return b.obj(); } virtual string json() const { return "{ \"$where\" : 1 }"; } }; DBTEST_SHIM_TEST(OkDollarFieldName); class SingleNumber : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", 1); return b.obj(); } virtual string json() const { return "{ \"a\" : 1 }"; } }; DBTEST_SHIM_TEST(SingleNumber); class RealNumber : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", strtod("0.7", 0)); return b.obj(); } virtual string json() const { return "{ \"a\" : 0.7 }"; } }; DBTEST_SHIM_TEST(RealNumber); class FancyNumber : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", strtod("-4.4433e-2", 0)); return b.obj(); } virtual string json() const { return "{ \"a\" : -4.4433e-2 }"; } }; DBTEST_SHIM_TEST(FancyNumber); class TwoElements : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", 1); b.append("b", "foo"); return b.obj(); } virtual string json() const { return "{ \"a\" : 1, \"b\" : \"foo\" }"; } }; DBTEST_SHIM_TEST(TwoElements); class Subobject : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", 1); BSONObjBuilder c; c.append("z", b.done()); return c.obj(); } virtual string json() const { return "{ \"z\" : { \"a\" : 1 } }"; } }; DBTEST_SHIM_TEST(Subobject); class DeeplyNestedObject : public Base { virtual string buildJson(int depth) const { if (depth == 0) { return "{\"0\":true}"; } else { std::stringstream ss; ss << "{\"" << depth << "\":" << buildJson(depth - 1) << "}"; depth--; return ss.str(); } } virtual BSONObj buildBson(int depth) const { BSONObjBuilder builder; if (depth == 0) { builder.append("0", true); return builder.obj(); } else { std::stringstream ss; ss << depth; depth--; builder.append(ss.str(), buildBson(depth)); return builder.obj(); } } virtual BSONObj bson() const { return buildBson(35); } virtual string json() const { return buildJson(35); } }; DBTEST_SHIM_TEST(DeeplyNestedObject); class ArrayEmpty : public Base { virtual BSONObj bson() const { vector arr; BSONObjBuilder b; b.append("a", arr); return b.obj(); } virtual string json() const { return "{ \"a\" : [] }"; } }; DBTEST_SHIM_TEST(ArrayEmpty); class TopLevelArrayEmpty : public Base { virtual BSONObj bson() const { return BSONArray(); } virtual string json() const { return "[]"; } }; DBTEST_SHIM_TEST(TopLevelArrayEmpty); class TopLevelArray : public Base { virtual BSONObj bson() const { BSONArrayBuilder builder; builder.append(123); builder.append("abc"); return builder.arr(); } virtual string json() const { return "[ 123, \"abc\" ]"; } }; DBTEST_SHIM_TEST(TopLevelArray); class Array : public Base { virtual BSONObj bson() const { vector arr; arr.push_back(1); arr.push_back(2); arr.push_back(3); BSONObjBuilder b; b.append("a", arr); return b.obj(); } virtual string json() const { return "{ \"a\" : [ 1, 2, 3 ] }"; } }; DBTEST_SHIM_TEST(Array); class True : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendBool("a", true); return b.obj(); } virtual string json() const { return "{ \"a\" : true }"; } }; DBTEST_SHIM_TEST(True); class False : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendBool("a", false); return b.obj(); } virtual string json() const { return "{ \"a\" : false }"; } }; DBTEST_SHIM_TEST(False); class Null : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNull("a"); return b.obj(); } virtual string json() const { return "{ \"a\" : null }"; } }; DBTEST_SHIM_TEST(Null); class Undefined : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendUndefined("a"); return b.obj(); } virtual string json() const { return "{ \"a\" : undefined }"; } }; DBTEST_SHIM_TEST(Undefined); class UndefinedStrict : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendUndefined("a"); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$undefined\" : true } }"; } }; DBTEST_SHIM_TEST(UndefinedStrict); class UndefinedStrictBad : public Bad { virtual string json() const { return "{ \"a\" : { \"$undefined\" : false } }"; } }; DBTEST_SHIM_TEST(UndefinedStrictBad); class EscapedCharacters : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", "\" \\ / \b \f \n \r \t \v"); return b.obj(); } virtual string json() const { return "{ \"a\" : \"\\\" \\\\ \\/ \\b \\f \\n \\r \\t \\v\" }"; } }; DBTEST_SHIM_TEST(EscapedCharacters); class NonEscapedCharacters : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", "% { a z $ # ' "); return b.obj(); } virtual string json() const { return "{ \"a\" : \"\\% \\{ \\a \\z \\$ \\# \\' \\ \" }"; } }; DBTEST_SHIM_TEST(NonEscapedCharacters); class AllowedControlCharacter : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a", "\x7f"); return b.obj(); } virtual string json() const { return "{ \"a\" : \"\x7f\" }"; } }; DBTEST_SHIM_TEST(AllowedControlCharacter); class InvalidControlCharacter : public Bad { virtual string json() const { return "{ \"a\" : \"\x1f\" }"; } }; DBTEST_SHIM_TEST(InvalidControlCharacter); class NumbersInFieldName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("b1", "b"); return b.obj(); } virtual string json() const { return "{ b1 : \"b\" }"; } }; DBTEST_SHIM_TEST(NumbersInFieldName); class EscapeFieldName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("\n", "b"); return b.obj(); } virtual string json() const { return "{ \"\\n\" : \"b\" }"; } }; DBTEST_SHIM_TEST(EscapeFieldName); class EscapedUnicodeToUtf8 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; unsigned char u[7]; u[0] = 0xe0 | 0x0a; u[1] = 0x80; u[2] = 0x80; u[3] = 0xe0 | 0x0a; u[4] = 0x80; u[5] = 0x80; u[6] = 0; b.append("a", (char*)u); BSONObj built = b.obj(); // ASSERT_EQUALS( string( (char *) u ), built.firstElement().valuestr() ); return built; } virtual string json() const { return "{ \"a\" : \"\\ua000\\uA000\" }"; } }; DBTEST_SHIM_TEST(EscapedUnicodeToUtf8); class Utf8AllOnes : public Base { virtual BSONObj bson() const { BSONObjBuilder b; unsigned char u[8]; u[0] = 0x01; u[1] = 0x7f; u[2] = 0xdf; u[3] = 0xbf; u[4] = 0xef; u[5] = 0xbf; u[6] = 0xbf; u[7] = 0; b.append("a", (char*)u); return b.obj(); } virtual string json() const { return "{ \"a\" : \"\\u0001\\u007f\\u07ff\\uffff\" }"; } }; DBTEST_SHIM_TEST(Utf8AllOnes); class Utf8FirstByteOnes : public Base { virtual BSONObj bson() const { BSONObjBuilder b; unsigned char u[6]; u[0] = 0xdc; u[1] = 0x80; u[2] = 0xef; u[3] = 0xbc; u[4] = 0x80; u[5] = 0; b.append("a", (char*)u); return b.obj(); } virtual string json() const { return "{ \"a\" : \"\\u0700\\uff00\" }"; } }; DBTEST_SHIM_TEST(Utf8FirstByteOnes); class Utf8Invalid : public Bad { virtual string json() const { return "{ \"a\" : \"\\u0ZZZ\" }"; } }; DBTEST_SHIM_TEST(Utf8Invalid); class Utf8TooShort : public Bad { virtual string json() const { return "{ \"a\" : \"\\u000\" }"; } }; DBTEST_SHIM_TEST(Utf8TooShort); class DBRefConstructor : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : Dbref( \"ns\", \"000000000000000000000000\" ) }"; } }; DBTEST_SHIM_TEST(DBRefConstructor); // Added for consistency with the mongo shell class DBRefConstructorCapitals : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : DBRef( \"ns\", \"000000000000000000000000\" ) }"; } }; DBTEST_SHIM_TEST(DBRefConstructorCapitals); class DBRefConstructorDbName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", "000000000000000000000000"); subBuilder.append("$db", "dbname"); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : Dbref( \"ns\", \"000000000000000000000000\", \"dbname\" ) }"; } }; DBTEST_SHIM_TEST(DBRefConstructorDbName); class DBRefConstructorNumber : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", 1); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : Dbref( \"ns\", 1 ) }"; } }; DBTEST_SHIM_TEST(DBRefConstructorNumber); class DBRefConstructorObject : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); BSONObjBuilder idSubBuilder(subBuilder.subobjStart("$id")); idSubBuilder.append("b", true); idSubBuilder.done(); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : Dbref( \"ns\", { \"b\" : true } ) }"; } }; DBTEST_SHIM_TEST(DBRefConstructorObject); class DBRefNumberId : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", 1); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : 1 } }"; } }; DBTEST_SHIM_TEST(DBRefNumberId); class DBRefObjectAsId : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); BSONObjBuilder idSubBuilder(subBuilder.subobjStart("$id")); idSubBuilder.append("b", true); idSubBuilder.done(); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : { \"b\" : true } } }"; } }; DBTEST_SHIM_TEST(DBRefObjectAsId); class DBRefStringId : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : \"000000000000000000000000\" } }"; } }; DBTEST_SHIM_TEST(DBRefStringId); class DBRefObjectIDObject : public Base { virtual BSONObj bson() const { BSONObjBuilder b; OID o; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", o); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : { \"$oid\" : \"000000000000000000000000\" " "} } }"; } }; DBTEST_SHIM_TEST(DBRefObjectIDObject); class DBRefObjectIDConstructor : public Base { virtual BSONObj bson() const { BSONObjBuilder b; OID o; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", o); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : ObjectId( \"000000000000000000000000\" ) " "} }"; } }; DBTEST_SHIM_TEST(DBRefObjectIDConstructor); class DBRefDbName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); subBuilder.append("$id", "000000000000000000000000"); subBuilder.append("$db", "dbname"); subBuilder.done(); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : \"000000000000000000000000\"" ", \"$db\" : \"dbname\" } }"; } }; DBTEST_SHIM_TEST(DBRefDbName); class Oid : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendOID("_id"); return b.obj(); } virtual string json() const { return "{ \"_id\" : { \"$oid\" : \"000000000000000000000000\" } }"; } }; DBTEST_SHIM_TEST(Oid); class Oid2 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; char OIDbytes[OID::kOIDSize]; memset(&OIDbytes, 0x0f, OID::kOIDSize); OID o = OID::from(OIDbytes); b.appendOID("_id", &o); return b.obj(); } virtual string json() const { return "{ \"_id\" : ObjectId( \"0f0f0f0f0f0f0f0f0f0f0f0f\" ) }"; } }; DBTEST_SHIM_TEST(Oid2); class OidTooLong : public Bad { virtual string json() const { return "{ \"_id\" : { \"$oid\" : \"0000000000000000000000000\" } }"; } }; DBTEST_SHIM_TEST(OidTooLong); class Oid2TooLong : public Bad { virtual string json() const { return "{ \"_id\" : ObjectId( \"0f0f0f0f0f0f0f0f0f0f0f0f0\" ) }"; } }; DBTEST_SHIM_TEST(Oid2TooLong); class OidTooShort : public Bad { virtual string json() const { return "{ \"_id\" : { \"$oid\" : \"00000000000000000000000\" } }"; } }; DBTEST_SHIM_TEST(OidTooShort); class Oid2TooShort : public Bad { virtual string json() const { return "{ \"_id\" : ObjectId( \"0f0f0f0f0f0f0f0f0f0f0f0\" ) }"; } }; DBTEST_SHIM_TEST(Oid2TooShort); class OidInvalidChar : public Bad { virtual string json() const { return "{ \"_id\" : { \"$oid\" : \"00000000000Z000000000000\" } }"; } }; DBTEST_SHIM_TEST(OidInvalidChar); class Oid2InvalidChar : public Bad { virtual string json() const { return "{ \"_id\" : ObjectId( \"0f0f0f0f0f0fZf0f0f0f0f0f\" ) }"; } }; DBTEST_SHIM_TEST(Oid2InvalidChar); class StringId : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("_id", "000000000000000000000000"); return b.obj(); } virtual string json() const { return "{ \"_id\" : \"000000000000000000000000\" }"; } }; DBTEST_SHIM_TEST(StringId); class BinData : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, BinDataGeneral, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"00\" } }"; } }; class BinData1 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, Function, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"01\" } }"; } }; DBTEST_SHIM_TEST(BinData1); class BinData2 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, ByteArrayDeprecated, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"02\" } }"; } }; DBTEST_SHIM_TEST(BinData2); class BinData3 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, bdtUUID, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"03\" } }"; } }; DBTEST_SHIM_TEST(BinData3); class BinData4 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, newUUID, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"04\" } }"; } }; DBTEST_SHIM_TEST(BinData4); class BinData5 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, MD5Type, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"05\" } }"; } }; DBTEST_SHIM_TEST(BinData5); class BinData80 : public Base { virtual BSONObj bson() const { char z[3]; z[0] = 'a'; z[1] = 'b'; z[2] = 'c'; BSONObjBuilder b; b.appendBinData("a", 3, bdtCustom, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"80\" } }"; } }; DBTEST_SHIM_TEST(BinData80); class BinDataPaddedSingle : public Base { virtual BSONObj bson() const { char z[2]; z[0] = 'a'; z[1] = 'b'; BSONObjBuilder b; b.appendBinData("a", 2, BinDataGeneral, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YWI=\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataPaddedSingle); class BinDataPaddedDouble : public Base { virtual BSONObj bson() const { char z[1]; z[0] = 'a'; BSONObjBuilder b; b.appendBinData("a", 1, BinDataGeneral, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQ==\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataPaddedDouble); class BinDataAllChars : public Base { virtual BSONObj bson() const { unsigned char z[] = {0x00, 0x10, 0x83, 0x10, 0x51, 0x87, 0x20, 0x92, 0x8B, 0x30, 0xD3, 0x8F, 0x41, 0x14, 0x93, 0x51, 0x55, 0x97, 0x61, 0x96, 0x9B, 0x71, 0xD7, 0x9F, 0x82, 0x18, 0xA3, 0x92, 0x59, 0xA7, 0xA2, 0x9A, 0xAB, 0xB2, 0xDB, 0xAF, 0xC3, 0x1C, 0xB3, 0xD3, 0x5D, 0xB7, 0xE3, 0x9E, 0xBB, 0xF3, 0xDF, 0xBF}; BSONObjBuilder b; b.appendBinData("a", 48, BinDataGeneral, z); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$binary\" : " "\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\", \"$type\" : " "\"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataAllChars); class BinDataBadLength : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQ=\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength); class BinDataBadLength1 : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQ\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength1); class BinDataBadLength2 : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQX==\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength2); class BinDataBadLength3 : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQX\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength3); class BinDataBadLength4 : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQXZ=\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength4); class BinDataBadLength5 : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"YQXZ==\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadLength5); class BinDataBadChars : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"a...\", \"$type\" : \"00\" } }"; } }; DBTEST_SHIM_TEST(BinDataBadChars); class BinDataTypeTooShort : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\", \"$type\" : \"0\" } }"; } }; DBTEST_SHIM_TEST(BinDataTypeTooShort); class BinDataTypeTooLong : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\", \"$type\" : \"000\" } }"; } }; DBTEST_SHIM_TEST(BinDataTypeTooLong); class BinDataTypeBadChars : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\", \"$type\" : \"ZZ\" } }"; } }; DBTEST_SHIM_TEST(BinDataTypeBadChars); class BinDataEmptyType : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\", \"$type\" : \"\" } }"; } }; DBTEST_SHIM_TEST(BinDataEmptyType); class BinDataNoType : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\" } }"; } }; DBTEST_SHIM_TEST(BinDataNoType); class BinDataInvalidType : public Bad { virtual string json() const { return "{ \"a\" : { \"$binary\" : \"AAAA\", \"$type\" : \"100\" } }"; } }; DBTEST_SHIM_TEST(BinDataInvalidType); class Date : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", 0); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$date\" : 0 } }"; } }; // DBTEST_SHIM_TEST(Date); SEE COMMENT IN OLD TEST REGISTRATION SECTION class DateNegZero : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", -0); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$date\" : -0 } }"; } }; // DBTEST_SHIM_TEST(DateNegZero); SEE COMMENT IN OLD TEST REGISTRATION SECTION class DateNonzero : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", 1000000000); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$date\" : 1000000000 } }"; } }; DBTEST_SHIM_TEST(DateNonzero); class DateStrictTooLong : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : { \"$date\" : " << ~(0ULL) << "1" << " } }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateStrictTooLong); class DateTooLong : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : Date( " << ~(0ULL) << "1" << " ) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateTooLong); class DateIsString : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : { \"$date\" : \"100\" } }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsString); class DateIsString1 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : Date(\"a\") }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsString1); class DateIsString2 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : new Date(\"a\") }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsString2); class DateIsFloat : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : { \"$date\" : 1.1 } }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsFloat); class DateIsFloat1 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : Date(1.1) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsFloat1); class DateIsFloat2 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : new Date(1.1) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsFloat2); class DateIsExponent : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : { \"$date\" : 10e3 } }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsExponent); class DateIsExponent1 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : Date(10e3) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsExponent1); class DateIsExponent2 : public Bad { virtual string json() const { stringstream ss; ss << "{ \"a\" : new Date(10e3) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateIsExponent2); /* Need to handle this because jsonString outputs the value of Date_t as unsigned. * See SERVER-8330 and SERVER-8573 */ class DateStrictMaxUnsigned : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", -1); return b.obj(); } virtual string json() const { stringstream ss; ss << "{ \"a\" : { \"$date\" : " << std::numeric_limits::max() << " } }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateStrictMaxUnsigned); class DateMaxUnsigned : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", -1); return b.obj(); } virtual string json() const { stringstream ss; ss << "{ \"a\" : Date( " << std::numeric_limits::max() << " ) }"; return ss.str(); } }; DBTEST_SHIM_TEST(DateMaxUnsigned); class DateStrictNegative : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", -1); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$date\" : -1 } }"; } }; DBTEST_SHIM_TEST(DateStrictNegative); class DateNegative : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendDate("a", -1); return b.obj(); } virtual string json() const { return "{ \"a\" : Date( -1 ) }"; } }; DBTEST_SHIM_TEST(DateNegative); class NumberLongTest : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", 20000LL); return b.obj(); } virtual string json() const { return "{ \"a\" : NumberLong( 20000 ) }"; } }; DBTEST_SHIM_TEST(NumberLongTest); class NumberLongMin : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", std::numeric_limits::min()); return b.obj(); } virtual string json() const { std::stringstream ss; ss << "{'a': NumberLong("; ss << std::numeric_limits::min(); ss << ") }"; return ss.str(); } }; DBTEST_SHIM_TEST(NumberLongMin); class NumberIntTest : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", 20000); return b.obj(); } virtual string json() const { return "{ \"a\" : NumberInt( 20000 ) }"; } }; DBTEST_SHIM_TEST(NumberIntTest); class NumberLongNeg : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", -20000LL); return b.obj(); } virtual string json() const { return "{ \"a\" : NumberLong( -20000 ) }"; } }; DBTEST_SHIM_TEST(NumberLongNeg); class NumberIntNeg : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", -20000); return b.obj(); } virtual string json() const { return "{ \"a\" : NumberInt( -20000 ) }"; } }; DBTEST_SHIM_TEST(NumberIntNeg); class NumberLongBad : public Bad { virtual string json() const { return "{ \"a\" : NumberLong( 'sdf' ) }"; } }; DBTEST_SHIM_TEST(NumberLongBad); class NumberIntBad : public Bad { virtual string json() const { return "{ \"a\" : NumberInt( 'sdf' ) }"; } }; DBTEST_SHIM_TEST(NumberIntBad); class Timestamp : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendTimestamp("a", Timestamp_t(20, 5)); return b.obj(); } virtual string json() const { return "{ \"a\" : Timestamp( 20, 5 ) }"; } }; DBTEST_SHIM_TEST(Timestamp); class TimestampNoIncrement : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( 20 ) }"; } }; DBTEST_SHIM_TEST(TimestampNoIncrement); class TimestampZero : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendTimestamp("a", Timestamp_t()); return b.obj(); } virtual string json() const { return "{ \"a\" : Timestamp( 0, 0 ) }"; } }; DBTEST_SHIM_TEST(TimestampZero); class TimestampNoArgs : public Bad { virtual string json() const { return "{ \"a\" : Timestamp() }"; } }; DBTEST_SHIM_TEST(TimestampNoArgs); class TimestampFloatSeconds : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( 20.0, 1 ) }"; } }; DBTEST_SHIM_TEST(TimestampFloatSeconds); class TimestampFloatIncrement : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( 20, 1.0 ) }"; } }; DBTEST_SHIM_TEST(TimestampFloatIncrement); class TimestampNegativeSeconds : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( -20, 5 ) }"; } }; DBTEST_SHIM_TEST(TimestampNegativeSeconds); class TimestampNegativeIncrement : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( 20, -5 ) }"; } }; DBTEST_SHIM_TEST(TimestampNegativeIncrement); class TimestampInvalidSeconds : public Bad { virtual string json() const { return "{ \"a\" : Timestamp( q, 5 ) }"; } }; DBTEST_SHIM_TEST(TimestampInvalidSeconds); class TimestampObject : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendTimestamp("a", Timestamp_t(20, 5)); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 20 , \"i\" : 5 } } }"; } }; DBTEST_SHIM_TEST(TimestampObject); class TimestampObjectInvalidFieldName : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"time\" : 20 , \"increment\" : 5 } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectInvalidFieldName); class TimestampObjectNoIncrement : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 20 } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectNoIncrement); class TimestampObjectNegativeSeconds : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : -20 , \"i\" : 5 } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectNegativeSeconds); class TimestampObjectNegativeIncrement : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 20 , \"i\" : -5 } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectNegativeIncrement); class TimestampObjectInvalidSeconds : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : q , \"i\" : 5 } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectInvalidSeconds); class TimestampObjectZero : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendTimestamp("a", Timestamp_t()); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 0, \"i\" : 0} } }"; } }; DBTEST_SHIM_TEST(TimestampObjectZero); class TimestampObjectNoArgs : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { } } }"; } }; DBTEST_SHIM_TEST(TimestampObjectNoArgs); class TimestampObjectFloatSeconds : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 1.0, \"i\" : 0} } }"; } }; DBTEST_SHIM_TEST(TimestampObjectFloatSeconds); class TimestampObjectFloatIncrement : public Bad { virtual string json() const { return "{ \"a\" : { \"$timestamp\" : { \"t\" : 20, \"i\" : 1.0} } }"; } }; DBTEST_SHIM_TEST(TimestampObjectFloatIncrement); class Regex : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "b", "i"); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"i\" } }"; } }; DBTEST_SHIM_TEST(Regex); class RegexNoOptionField : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "b", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\" } }"; } }; DBTEST_SHIM_TEST(RegexNoOptionField); class RegexEscape : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "\t", "i"); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$regex\" : \"\\t\", \"$options\" : \"i\" } }"; } }; DBTEST_SHIM_TEST(RegexEscape); class RegexWithQuotes : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "\"", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : /\"/ }"; } }; DBTEST_SHIM_TEST(RegexWithQuotes); class RegexWithQuotes1 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "\"", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : { $regex : \"\\\"\" }}"; } }; DBTEST_SHIM_TEST(RegexWithQuotes1); class RegexInvalidField : public Bad { virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\", \"field\" : \"i\" } }"; } }; DBTEST_SHIM_TEST(RegexInvalidField); class RegexInvalidOption : public Bad { virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"1\" } }"; } }; DBTEST_SHIM_TEST(RegexInvalidOption); class RegexInvalidOption2 : public Bad { virtual string json() const { return "{ \"a\" : /b/c }"; } }; DBTEST_SHIM_TEST(RegexInvalidOption2); class RegexInvalidOption3 : public Bad { virtual string json() const { return "{ \"a\" : /b/ic }"; } }; DBTEST_SHIM_TEST(RegexInvalidOption3); class RegexInvalidOption4 : public Bad { virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"a\" } }"; } }; DBTEST_SHIM_TEST(RegexInvalidOption4); class RegexInvalidOption5 : public Bad { virtual string json() const { return "{ \"a\" : /b/a }"; } }; DBTEST_SHIM_TEST(RegexInvalidOption5); class RegexEmptyOption : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "b", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"\" } }"; } }; DBTEST_SHIM_TEST(RegexEmptyOption); class RegexEmpty : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$regex\" : \"\", \"$options\" : \"\"} }"; } }; DBTEST_SHIM_TEST(RegexEmpty); class RegexEmpty1 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendRegex("a", "", ""); return b.obj(); } virtual string json() const { return "{ \"a\" : // }"; } }; DBTEST_SHIM_TEST(RegexEmpty1); class RegexOverlap : public Bad { virtual string json() const { return "{ \"a\" : { \"$regex\" : // } }"; } }; DBTEST_SHIM_TEST(RegexOverlap); class Malformed : public Bad { string json() const { return "{"; } }; DBTEST_SHIM_TEST(Malformed); class Malformed1 : public Bad { string json() const { return "}"; } }; DBTEST_SHIM_TEST(Malformed1); class Malformed2 : public Bad { string json() const { return "{test}"; } }; DBTEST_SHIM_TEST(Malformed2); class Malformed3 : public Bad { string json() const { return "{test"; } }; DBTEST_SHIM_TEST(Malformed3); class Malformed4 : public Bad { string json() const { return "{ test : 1"; } }; DBTEST_SHIM_TEST(Malformed4); class Malformed5 : public Bad { string json() const { return "{ test : 1 , }"; } }; DBTEST_SHIM_TEST(Malformed5); class Malformed6 : public Bad { string json() const { return "{ test : 1 , tst}"; } }; DBTEST_SHIM_TEST(Malformed6); class Malformed7 : public Bad { string json() const { return "{ a : []"; } }; DBTEST_SHIM_TEST(Malformed7); class Malformed8 : public Bad { string json() const { return "{ a : { test : 1 }"; } }; DBTEST_SHIM_TEST(Malformed8); class Malformed9 : public Bad { string json() const { return "{ a : [ { test : 1]}"; } }; DBTEST_SHIM_TEST(Malformed9); class Malformed10 : public Bad { string json() const { return "{ a : [ { test : 1], b : 2}"; } }; DBTEST_SHIM_TEST(Malformed10); class Malformed11 : public Bad { string json() const { return "{ a : \"test\"string }"; } }; DBTEST_SHIM_TEST(Malformed11); class Malformed12 : public Bad { string json() const { return "{ a : test\"string\" }"; } }; DBTEST_SHIM_TEST(Malformed12); class Malformed13 : public Bad { string json() const { return "{ a\"bad\" : \"teststring\" }"; } }; DBTEST_SHIM_TEST(Malformed13); class Malformed14 : public Bad { string json() const { return "{ \"a\"test : \"teststring\" }"; } }; DBTEST_SHIM_TEST(Malformed14); class Malformed15 : public Bad { string json() const { return "{ \"atest : \"teststring\" }"; } }; DBTEST_SHIM_TEST(Malformed15); class Malformed16 : public Bad { string json() const { return "{ atest\" : \"teststring\" }"; } }; DBTEST_SHIM_TEST(Malformed16); class Malformed17 : public Bad { string json() const { return "{ atest\" : 1 }"; } }; DBTEST_SHIM_TEST(Malformed17); class Malformed18 : public Bad { string json() const { return "{ atest : \"teststring }"; } }; DBTEST_SHIM_TEST(Malformed18); class Malformed19 : public Bad { string json() const { return "{ atest : teststring\" }"; } }; DBTEST_SHIM_TEST(Malformed19); class UnquotedFieldName : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("a_b", 1); return b.obj(); } virtual string json() const { return "{ a_b : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldName); class UnquotedFieldNameBad : public Bad { string json() const { return "{ 123 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad); class UnquotedFieldNameBad1 : public Bad { string json() const { return "{ -123 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad1); class UnquotedFieldNameBad2 : public Bad { string json() const { return "{ .123 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad2); class UnquotedFieldNameBad3 : public Bad { string json() const { return "{ -.123 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad3); class UnquotedFieldNameBad4 : public Bad { string json() const { return "{ -1.23 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad4); class UnquotedFieldNameBad5 : public Bad { string json() const { return "{ 1e23 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad5); class UnquotedFieldNameBad6 : public Bad { string json() const { return "{ -1e23 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad6); class UnquotedFieldNameBad7 : public Bad { string json() const { return "{ -1e-23 : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad7); class UnquotedFieldNameBad8 : public Bad { string json() const { return "{ -hello : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad8); class UnquotedFieldNameBad9 : public Bad { string json() const { return "{ il.legal : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad9); class UnquotedFieldNameBad10 : public Bad { string json() const { return "{ 10gen : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad10); class UnquotedFieldNameBad11 : public Bad { string json() const { return "{ _123. : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad11); class UnquotedFieldNameBad12 : public Bad { string json() const { return "{ he-llo : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad12); class UnquotedFieldNameBad13 : public Bad { string json() const { return "{ bad\nchar : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad13); class UnquotedFieldNameBad14 : public Bad { string json() const { return "{ thiswill\fail : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad14); class UnquotedFieldNameBad15 : public Bad { string json() const { return "{ failu\re : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad15); class UnquotedFieldNameBad16 : public Bad { string json() const { return "{ t\test : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad16); class UnquotedFieldNameBad17 : public Bad { string json() const { return "{ \break: 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad17); class UnquotedFieldNameBad18 : public Bad { string json() const { // here we fill the memory directly to test unicode values // In this case we set \u0700 and \uFF00 // Setting it directly in memory avoids MSVC error c4566 unsigned char u[6]; u[0] = 0xdc; u[1] = 0x80; u[2] = 0xef; u[3] = 0xbc; u[4] = 0x80; u[5] = 0; std::stringstream ss; ss << "{ " << u << " : 1 }"; return ss.str(); } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad18); class UnquotedFieldNameBad19 : public Bad { string json() const { return "{ bl\\u3333p: 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad19); class UnquotedFieldNameBad20 : public Bad { string json() const { return "{ bl-33p: 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameBad20); class UnquotedFieldNameDollar : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("$a_b", 1); return b.obj(); } virtual string json() const { return "{ $a_b : 1 }"; } }; DBTEST_SHIM_TEST(UnquotedFieldNameDollar); class SingleQuotes : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("ab'c\"", "bb\b '\""); return b.obj(); } virtual string json() const { return "{ 'ab\\'c\"' : 'bb\\b \\'\"' }"; } }; DBTEST_SHIM_TEST(SingleQuotes); class QuoteTest : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("\"", "test"); return b.obj(); } virtual string json() const { return "{ '\"' : \"test\" }"; } }; DBTEST_SHIM_TEST(QuoteTest); class QuoteTest1 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("'", "test"); return b.obj(); } virtual string json() const { return "{ \"'\" : \"test\" }"; } }; DBTEST_SHIM_TEST(QuoteTest1); class QuoteTest2 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("\"", "test"); return b.obj(); } virtual string json() const { return "{ '\"' : \"test\" }"; } }; DBTEST_SHIM_TEST(QuoteTest2); class QuoteTest3 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("\"'\"", "test"); return b.obj(); } virtual string json() const { return "{ '\"\\\'\"' : \"test\" }"; } }; DBTEST_SHIM_TEST(QuoteTest3); class QuoteTest4 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("'\"'", "test"); return b.obj(); } virtual string json() const { return "{ \"'\\\"'\" : \"test\" }"; } }; DBTEST_SHIM_TEST(QuoteTest4); class QuoteTest5 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("test", "'"); return b.obj(); } virtual string json() const { return "{ \"test\" : \"'\" }"; } }; DBTEST_SHIM_TEST(QuoteTest5); class QuoteTest6 : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("test", "\""); return b.obj(); } virtual string json() const { return "{ \"test\" : '\"' }"; } }; DBTEST_SHIM_TEST(QuoteTest6); class ObjectId : public Base { virtual BSONObj bson() const { OID id; id.init("deadbeeff00ddeadbeeff00d"); BSONObjBuilder b; b.appendOID("_id", &id); return b.obj(); } virtual string json() const { return "{ \"_id\": ObjectId( \"deadbeeff00ddeadbeeff00d\" ) }"; } }; DBTEST_SHIM_TEST(ObjectId); class ObjectId2 : public Base { virtual BSONObj bson() const { OID id; id.init("deadbeeff00ddeadbeeff00d"); BSONObjBuilder b; b.appendOID("foo", &id); return b.obj(); } virtual string json() const { return "{ \"foo\": ObjectId( \"deadbeeff00ddeadbeeff00d\" ) }"; } }; DBTEST_SHIM_TEST(ObjectId2); class NumericTypes : public Base { public: void run() { Base::run(); BSONObj o = fromjson(json()); ASSERT(o["int"].type() == NumberInt); ASSERT(o["long"].type() == NumberLong); ASSERT(o["double"].type() == NumberDouble); ASSERT(o["long"].numberLong() == 9223372036854775807ll); } virtual BSONObj bson() const { return BSON("int" << 123 << "long" << 9223372036854775807ll // 2**63 - 1 << "double" << 3.14); } virtual string json() const { return "{ \"int\": 123, \"long\": 9223372036854775807, \"double\": 3.14 }"; } }; DBTEST_SHIM_TEST(NumericTypes); class NumericTypesJS : public Base { public: void run() { Base::run(); BSONObj o = fromjson(json()); ASSERT(o["int"].type() == NumberInt); ASSERT(o["long"].type() == NumberLong); ASSERT(o["double"].type() == NumberDouble); ASSERT(o["long"].numberLong() == 9223372036854775807ll); } virtual BSONObj bson() const { return BSON("int" << 123 << "long" << 9223372036854775807ll // 2**63 - 1 << "double" << 3.14); } virtual string json() const { return "{ 'int': NumberInt(123), " "'long': NumberLong(9223372036854775807), " "'double': 3.14 }"; } }; DBTEST_SHIM_TEST(NumericTypesJS); class NumericLongMin : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", std::numeric_limits::min()); return b.obj(); } virtual string json() const { std::stringstream ss; ss << "{'a': "; ss << std::numeric_limits::min(); ss << " }"; return ss.str(); } }; DBTEST_SHIM_TEST(NumericLongMin); class NumericIntMin : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendNumber("a", std::numeric_limits::min()); return b.obj(); } virtual string json() const { std::stringstream ss; ss << "{'a': "; ss << std::numeric_limits::min(); ss << " }"; return ss.str(); } }; DBTEST_SHIM_TEST(NumericIntMin); class NumericLimits : public Base { virtual BSONObj bson() const { BSONObjBuilder builder; BSONArrayBuilder numArray(builder.subarrayStart("")); numArray.append(std::numeric_limits::max()); numArray.append(std::numeric_limits::min()); numArray.append(std::numeric_limits::max()); numArray.append(std::numeric_limits::min()); numArray.done(); return builder.obj(); } virtual string json() const { std::stringstream ss; ss << "{'': ["; ss << std::numeric_limits::max() << ","; ss << std::numeric_limits::min() << ","; ss << std::numeric_limits::max() << ","; ss << std::numeric_limits::min(); ss << "] }"; return ss.str(); } }; DBTEST_SHIM_TEST(NumericLimits); // Overflows double by giving it an exponent that is too large class NumericLimitsBad : public Bad { virtual string json() const { std::stringstream ss; ss << "{ test : "; ss << std::numeric_limits::max() << "1111111111"; ss << "}"; return ss.str(); } }; DBTEST_SHIM_TEST(NumericLimitsBad); class NumericLimitsBad1 : public Bad { virtual string json() const { std::stringstream ss; ss << "{ test : "; ss << std::numeric_limits::min() << "11111111111"; ss << "}"; return ss.str(); } }; DBTEST_SHIM_TEST(NumericLimitsBad1); class NegativeNumericTypes : public Base { public: void run() { Base::run(); BSONObj o = fromjson(json()); ASSERT(o["int"].type() == NumberInt); ASSERT(o["long"].type() == NumberLong); ASSERT(o["double"].type() == NumberDouble); ASSERT(o["long"].numberLong() == -9223372036854775807ll); } virtual BSONObj bson() const { return BSON("int" << -123 << "long" << -9223372036854775807ll // -1 * (2**63 - 1) << "double" << -3.14); } virtual string json() const { return "{ \"int\": -123, \"long\": -9223372036854775807, \"double\": -3.14 }"; } }; DBTEST_SHIM_TEST(NegativeNumericTypes); class EmbeddedDatesBase : public Base { public: virtual void run() { BSONObj o = fromjson(json()); ASSERT_EQUALS(3, (o["time.valid"].type())); BSONObj e = o["time.valid"].embeddedObjectUserCheck(); ASSERT_EQUALS(9, e["$gt"].type()); ASSERT_EQUALS(9, e["$lt"].type()); Base::run(); } BSONObj bson() const { BSONObjBuilder e; e.appendDate("$gt", 1257829200000LL); e.appendDate("$lt", 1257829200100LL); BSONObjBuilder b; b.append("time.valid", e.obj()); return b.obj(); } virtual string json() const = 0; }; struct EmbeddedDatesFormat1 : EmbeddedDatesBase { string json() const { return "{ \"time.valid\" : { $gt : { \"$date\" : 1257829200000 } , $lt : { \"$date\" : " "1257829200100 } } }"; } }; DBTEST_SHIM_TEST(EmbeddedDatesFormat1); struct EmbeddedDatesFormat2 : EmbeddedDatesBase { string json() const { return "{ \"time.valid\" : { $gt : Date(1257829200000) , $lt : Date( 1257829200100 ) } }"; } }; DBTEST_SHIM_TEST(EmbeddedDatesFormat2); struct EmbeddedDatesFormat3 : EmbeddedDatesBase { string json() const { return "{ \"time.valid\" : { $gt : new Date(1257829200000) , $lt : new Date( 1257829200100 " ") } }"; } }; DBTEST_SHIM_TEST(EmbeddedDatesFormat3); class NullString : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.append("x", "a\0b", 4); return b.obj(); } virtual string json() const { return "{ \"x\" : \"a\\u0000b\" }"; } }; DBTEST_SHIM_TEST(NullString); class NullFieldUnquoted : public Bad { virtual string json() const { return "{ x\\u0000y : \"a\" }"; } }; DBTEST_SHIM_TEST(NullFieldUnquoted); class MinKeyAlone : public Bad { virtual string json() const { return "{ \"$minKey\" : 1 }"; } }; DBTEST_SHIM_TEST(MinKeyAlone); class MaxKeyAlone : public Bad { virtual string json() const { return "{ \"$maxKey\" : 1 }"; } }; DBTEST_SHIM_TEST(MaxKeyAlone); class MinKey : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendMinKey("a"); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$minKey\" : 1 } }"; } }; DBTEST_SHIM_TEST(MinKey); class MaxKey : public Base { virtual BSONObj bson() const { BSONObjBuilder b; b.appendMaxKey("a"); return b.obj(); } virtual string json() const { return "{ \"a\" : { \"$maxKey\" : 1 } }"; } }; DBTEST_SHIM_TEST(MaxKey); } // namespace FromJsonTests } // namespace JsonTests mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/000077500000000000000000000000001273231111400224675ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_conn_registry.cpp000066400000000000000000000057451273231111400271040ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/base/init.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" namespace mongo { using std::string; boost::scoped_ptr MockConnRegistry::_instance; MONGO_INITIALIZER(MockConnRegistry)(InitializerContext* context) { return MockConnRegistry::init(); } Status MockConnRegistry::init() { MockConnRegistry::_instance.reset(new MockConnRegistry()); return Status::OK(); } MockConnRegistry::MockConnRegistry() : _mockConnStrHook(this), _registryMutex() {} MockConnRegistry* MockConnRegistry::get() { return _instance.get(); } ConnectionString::ConnectionHook* MockConnRegistry::getConnStrHook() { return &_mockConnStrHook; } void MockConnRegistry::addServer(MockRemoteDBServer* server) { boost::lock_guard sl(_registryMutex); const std::string hostName(server->getServerAddress()); fassert(16533, _registry.count(hostName) == 0); _registry[hostName] = server; } bool MockConnRegistry::removeServer(const std::string& hostName) { boost::lock_guard sl(_registryMutex); return _registry.erase(hostName) == 1; } void MockConnRegistry::clear() { boost::lock_guard sl(_registryMutex); _registry.clear(); } MockDBClientConnection* MockConnRegistry::connect(const std::string& connStr) { boost::lock_guard sl(_registryMutex); fassert(16534, _registry.count(connStr) == 1); return new MockDBClientConnection(_registry[connStr], true); } MockConnRegistry::MockConnHook::MockConnHook(MockConnRegistry* registry) : _registry(registry) {} MockConnRegistry::MockConnHook::~MockConnHook() {} mongo::DBClientBase* MockConnRegistry::MockConnHook::connect(const ConnectionString& connString, std::string& errmsg, double socketTimeout) { const string hostName(connString.toString()); MockDBClientConnection* conn = _registry->connect(hostName); if (!conn->connect(hostName.c_str(), errmsg)) { // Assumption: connect never throws, so no leak. delete conn; // mimic ConnectionString::connect for MASTER type connection to return NULL // if the destination is unreachable. return NULL; } return conn; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_conn_registry.h000066400000000000000000000062241273231111400265420ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/status.h" #include "mongo/client/dbclientinterface.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/dbtests/mock/mock_remote_db_server.h" #include "mongo/platform/unordered_map.h" namespace mongo { /** * Registry for storing mock servers and can create mock connections to these * servers. */ class MockConnRegistry { public: /** * Initializes the static instance. */ static Status init(); /** * @return the singleton registry. If this needs to be called before main(), * then the initializer method should depend on "MockConnRegistry". */ static MockConnRegistry* get(); /** * Adds a server to this registry. * * @param server the server to add. Caller is responsible for disposing * the server. */ void addServer(MockRemoteDBServer* server); /** * Removes the server from this registry. * * @param hostName the host name of the server to remove. * * @return true if the server is in the registry and was removed. */ bool removeServer(const std::string& hostName); /** * Clears the registry. */ void clear(); /** * @return a new mocked connection to a server with the given hostName. */ MockDBClientConnection* connect(const std::string& hostName); /** * @return the hook that can be used with ConnectionString. */ ConnectionString::ConnectionHook* getConnStrHook(); private: class MockConnHook : public ConnectionString::ConnectionHook { public: /** * Creates a new connection hook for the ConnectionString class that * can create mock connections to mock replica set members using their * pseudo host names. * * @param replSet the mock replica set. Caller is responsible for managing * replSet and making sure that it lives longer than this object. */ MockConnHook(MockConnRegistry* registry); ~MockConnHook(); mongo::DBClientBase* connect(const mongo::ConnectionString& connString, std::string& errmsg, double socketTimeout); private: MockConnRegistry* _registry; }; MockConnRegistry(); static boost::scoped_ptr _instance; MockConnHook _mockConnStrHook; // protects _registry boost::mutex _registryMutex; unordered_map _registry; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_dbclient_connection.cpp000066400000000000000000000156041273231111400302150ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/client/write_options.h" #include "mongo/dbtests/mock/mock_dbclient_cursor.h" #include "mongo/util/net/sock.h" #include "mongo/util/time_support.h" using mongo::BSONObj; using std::string; using std::vector; namespace mongo { MockDBClientConnection::MockDBClientConnection(MockRemoteDBServer* remoteServer, bool autoReconnect) : _remoteServerInstanceID(remoteServer->getInstanceID()), _remoteServer(remoteServer), _isFailed(false), _sockCreationTime(mongo::curTimeMicros64()), _autoReconnect(autoReconnect) {} MockDBClientConnection::~MockDBClientConnection() {} bool MockDBClientConnection::connect(const char* hostName, std::string& errmsg) { if (_remoteServer->isRunning()) { _remoteServerInstanceID = _remoteServer->getInstanceID(); return true; } errmsg.assign("cannot connect to " + _remoteServer->getServerAddress()); return false; } bool MockDBClientConnection::runCommand(const string& dbname, const BSONObj& cmdObj, BSONObj& info, int options) { checkConnection(); try { return _remoteServer->runCommand(_remoteServerInstanceID, dbname, cmdObj, info, options); } catch (const mongo::SocketException&) { _isFailed = true; throw; } return false; } std::auto_ptr MockDBClientConnection::query(const string& ns, mongo::Query query, int nToReturn, int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, int batchSize) { checkConnection(); try { mongo::BSONArray result(_remoteServer->query(_remoteServerInstanceID, ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize)); std::auto_ptr cursor; cursor.reset(new MockDBClientCursor(this, result)); return cursor; } catch (const mongo::SocketException&) { _isFailed = true; throw; } std::auto_ptr nullPtr; return nullPtr; } mongo::ConnectionString::ConnectionType MockDBClientConnection::type() const { return mongo::ConnectionString::CUSTOM; } bool MockDBClientConnection::isFailed() const { return _isFailed; } string MockDBClientConnection::getServerAddress() const { return _remoteServer->getServerAddress(); } string MockDBClientConnection::toString() const { return _remoteServer->toString(); } unsigned long long MockDBClientConnection::query(stdx::function f, const string& ns, mongo::Query query, const BSONObj* fieldsToReturn, int queryOptions) { verify(false); return 0; } unsigned long long MockDBClientConnection::query( stdx::function f, const std::string& ns, mongo::Query query, const mongo::BSONObj* fieldsToReturn, int queryOptions) { verify(false); return 0; } uint64_t MockDBClientConnection::getSockCreationMicroSec() const { return _sockCreationTime; } void MockDBClientConnection::insert(const string& ns, BSONObj obj, int flags, const WriteConcern* wc) { _remoteServer->insert(ns, obj, flags); } void MockDBClientConnection::insert(const string& ns, const vector& objList, int flags, const WriteConcern* wc) { for (vector::const_iterator iter = objList.begin(); iter != objList.end(); ++iter) { insert(ns, *iter, flags); } } void MockDBClientConnection::remove(const string& ns, Query query, bool justOne, const WriteConcern* wc) { remove(ns, query, (justOne ? RemoveOption_JustOne : 0)); } void MockDBClientConnection::remove(const string& ns, Query query, int flags, const WriteConcern* wc) { _remoteServer->remove(ns, query, flags); } void MockDBClientConnection::killCursor(long long cursorID) { verify(false); // unimplemented } bool MockDBClientConnection::callRead(mongo::Message& toSend, mongo::Message& response) { verify(false); // unimplemented return false; } bool MockDBClientConnection::call(mongo::Message& toSend, mongo::Message& response, bool assertOk, string* actualServer) { verify(false); // unimplemented return false; } void MockDBClientConnection::say(mongo::Message& toSend, bool isRetry, string* actualServer) { verify(false); // unimplemented } void MockDBClientConnection::sayPiggyBack(mongo::Message& toSend) { verify(false); // unimplemented } bool MockDBClientConnection::lazySupported() const { verify(false); // unimplemented return false; } double MockDBClientConnection::getSoTimeout() const { return 0; } void MockDBClientConnection::checkConnection() { if (_isFailed && _autoReconnect) { _remoteServerInstanceID = _remoteServer->getInstanceID(); } } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_dbclient_connection.h000066400000000000000000000116611273231111400276610ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/client/dbclientinterface.h" #include "mongo/dbtests/mock/mock_remote_db_server.h" namespace mongo { /** * A simple class for mocking mongo::DBClientConnection. * * Also check out sample usage in dbtests/mock_dbclient_conn_test.cpp */ class MockDBClientConnection : public mongo::DBClientConnection { public: /** * Create a mock connection to a mock server. * * @param remoteServer the remote server to connect to. The caller is * responsible for making sure that the life of remoteServer is * longer than this connection. * @param autoReconnect will automatically re-establish connection the * next time an operation is requested when the last operation caused * this connection to fall into a failed state. */ MockDBClientConnection(MockRemoteDBServer* remoteServer, bool autoReconnect = false); virtual ~MockDBClientConnection(); // // DBClientBase methods // bool connect(const char* hostName, std::string& errmsg); inline bool connect(const HostAndPort& host, std::string& errmsg) { return connect(host.toString().c_str(), errmsg); } bool runCommand(const std::string& dbname, const mongo::BSONObj& cmdObj, mongo::BSONObj& info, int options = 0); std::auto_ptr query(const std::string& ns, mongo::Query query = mongo::Query(), int nToReturn = 0, int nToSkip = 0, const mongo::BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); uint64_t getSockCreationMicroSec() const; virtual void insert(const std::string& ns, BSONObj obj, int flags = 0, const WriteConcern* wc = NULL); virtual void insert(const std::string& ns, const std::vector& objList, int flags = 0, const WriteConcern* wc = NULL); virtual void remove(const std::string& ns, Query query, bool justOne = false, const WriteConcern* wc = NULL); virtual void remove(const std::string& ns, Query query, int flags = 0, const WriteConcern* wc = NULL); // // Getters // mongo::ConnectionString::ConnectionType type() const; bool isFailed() const; double getSoTimeout() const; std::string getServerAddress() const; std::string toString() const; // // Unsupported methods (defined to get rid of virtual function was hidden error) // unsigned long long query(stdx::function f, const std::string& ns, mongo::Query query, const mongo::BSONObj* fieldsToReturn = 0, int queryOptions = 0); unsigned long long query(stdx::function f, const std::string& ns, mongo::Query query, const mongo::BSONObj* fieldsToReturn = 0, int queryOptions = 0); // // Unsupported methods (these are pure virtuals in the base class) // void killCursor(long long cursorID); bool callRead(mongo::Message& toSend, mongo::Message& response); bool call(mongo::Message& toSend, mongo::Message& response, bool assertOk = true, std::string* actualServer = 0); void say(mongo::Message& toSend, bool isRetry = false, std::string* actualServer = 0); void sayPiggyBack(mongo::Message& toSend); bool lazySupported() const; private: void checkConnection(); MockRemoteDBServer::InstanceID _remoteServerInstanceID; MockRemoteDBServer* _remoteServer; bool _isFailed; uint64_t _sockCreationTime; bool _autoReconnect; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp000066400000000000000000000022631273231111400273700ustar00rootroot00000000000000//@file dbclientmockcursor.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/dbtests/mock/mock_dbclient_cursor.h" namespace mongo { MockDBClientCursor::MockDBClientCursor(mongo::DBClientBase* client, const mongo::BSONArray& resultSet) : mongo::DBClientCursor(client, "", 0, 0, 0, 0) { _resultSet = resultSet.copy(); _cursor.reset(new mongo::DBClientMockCursor(BSONArray(_resultSet))); } bool MockDBClientCursor::more() { return _cursor->more(); } mongo::BSONObj MockDBClientCursor::next() { return _cursor->next(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_dbclient_cursor.h000066400000000000000000000025571273231111400270430ustar00rootroot00000000000000//@file dbclientmockcursor.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientmockcursor.h" namespace mongo { /** * Simple adapter class for mongo::DBClientMockCursor to mongo::DBClientCursor. * Only supports more and next, the behavior of other operations are undefined. */ class MockDBClientCursor : public mongo::DBClientCursor { public: MockDBClientCursor(mongo::DBClientBase* client, const mongo::BSONArray& mockCollection); bool more(); /** * Note: has the same contract as DBClientCursor - returned BSONObj will * become invalid when this cursor is destroyed. */ mongo::BSONObj next(); private: boost::scoped_ptr _cursor; mongo::BSONObj _resultSet; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_remote_db_server.cpp000066400000000000000000000152131273231111400275340ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/dbtests/mock/mock_remote_db_server.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/sock.h" #include "mongo/util/time_support.h" using std::string; using std::vector; namespace mongo { MockRemoteDBServer::CircularBSONIterator::CircularBSONIterator(const vector& replyVector) { for (std::vector::const_iterator iter = replyVector.begin(); iter != replyVector.end(); ++iter) { _replyObjs.push_back(iter->copy()); } _iter = _replyObjs.begin(); } BSONObj MockRemoteDBServer::CircularBSONIterator::next() { verify(_iter != _replyObjs.end()); BSONObj reply = _iter->copy(); ++_iter; if (_iter == _replyObjs.end()) { _iter = _replyObjs.begin(); } return reply; } MockRemoteDBServer::MockRemoteDBServer(const string& hostAndPort) : _isRunning(true), _hostAndPort(hostAndPort), _delayMilliSec(0), _cmdCount(0), _queryCount(0), _instanceID(0), _lock() { insert(IdentityNS, BSON(HostField(hostAndPort)), 0); } MockRemoteDBServer::~MockRemoteDBServer() {} void MockRemoteDBServer::setDelay(long long milliSec) { boost::lock_guard sLock(_lock); _delayMilliSec = milliSec; } void MockRemoteDBServer::shutdown() { boost::lock_guard sLock(_lock); _isRunning = false; } void MockRemoteDBServer::reboot() { boost::lock_guard sLock(_lock); _isRunning = true; _instanceID++; } MockRemoteDBServer::InstanceID MockRemoteDBServer::getInstanceID() const { boost::lock_guard sLock(_lock); return _instanceID; } bool MockRemoteDBServer::isRunning() const { boost::lock_guard sLock(_lock); return _isRunning; } void MockRemoteDBServer::setCommandReply(const string& cmdName, const mongo::BSONObj& replyObj) { vector replySequence; replySequence.push_back(replyObj); setCommandReply(cmdName, replySequence); } void MockRemoteDBServer::setCommandReply(const string& cmdName, const vector& replySequence) { boost::lock_guard sLock(_lock); _cmdMap[cmdName].reset(new CircularBSONIterator(replySequence)); } void MockRemoteDBServer::insert(const string& ns, BSONObj obj, int flags) { boost::lock_guard sLock(_lock); vector& mockCollection = _dataMgr[ns]; mockCollection.push_back(obj.copy()); } void MockRemoteDBServer::remove(const string& ns, Query query, int flags) { boost::lock_guard sLock(_lock); if (_dataMgr.count(ns) == 0) { return; } _dataMgr.erase(ns); } bool MockRemoteDBServer::runCommand(MockRemoteDBServer::InstanceID id, const string& dbname, const BSONObj& cmdObj, BSONObj& info, int options) { checkIfUp(id); // Get the name of the command - copied from _runCommands @ db/dbcommands.cpp BSONObj innerCmdObj; { mongo::BSONElement e = cmdObj.firstElement(); if (e.type() == mongo::Object && (e.fieldName()[0] == '$' ? mongo::str::equals("query", e.fieldName() + 1) : mongo::str::equals("query", e.fieldName()))) { innerCmdObj = e.embeddedObject(); } else { innerCmdObj = cmdObj; } } string cmdName = innerCmdObj.firstElement().fieldName(); uassert(16430, str::stream() << "no reply for cmd: " << cmdName, _cmdMap.count(cmdName) == 1); { boost::lock_guard sLock(_lock); info = _cmdMap[cmdName]->next(); } if (_delayMilliSec > 0) { mongo::sleepmillis(_delayMilliSec); } checkIfUp(id); boost::lock_guard sLock(_lock); _cmdCount++; return info["ok"].trueValue(); } mongo::BSONArray MockRemoteDBServer::query(MockRemoteDBServer::InstanceID id, const string& ns, mongo::Query, /* don't support */ int nToReturn, int nToSkip, const BSONObj*, /* don't support */ int, /* don't support */ int) /* don't support */ { int seen = 0; checkIfUp(id); if (_delayMilliSec > 0) { mongo::sleepmillis(_delayMilliSec); } checkIfUp(id); boost::lock_guard sLock(_lock); _queryCount++; const vector& coll = _dataMgr[ns]; BSONArrayBuilder result; for (vector::const_iterator iter = coll.begin(); iter != coll.end(); ++iter) { if (nToSkip) { nToSkip--; } else { if (nToReturn && (seen == nToReturn)) break; result.append(iter->copy()); seen++; } } return BSONArray(result.obj()); } mongo::ConnectionString::ConnectionType MockRemoteDBServer::type() const { return mongo::ConnectionString::CUSTOM; } size_t MockRemoteDBServer::getCmdCount() const { boost::lock_guard sLock(_lock); return _cmdCount; } size_t MockRemoteDBServer::getQueryCount() const { boost::lock_guard sLock(_lock); return _queryCount; } void MockRemoteDBServer::clearCounters() { boost::lock_guard sLock(_lock); _cmdCount = 0; _queryCount = 0; } string MockRemoteDBServer::getServerAddress() const { return _hostAndPort; } string MockRemoteDBServer::toString() { return _hostAndPort; } void MockRemoteDBServer::checkIfUp(InstanceID id) const { boost::lock_guard sLock(_lock); if (!_isRunning || id < _instanceID) { throw mongo::SocketException(mongo::SocketException::CLOSED, _hostAndPort); } } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_remote_db_server.h000066400000000000000000000155311273231111400272040ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/bson/bson_field.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/client/dbclientinterface.h" #include "mongo/platform/unordered_map.h" namespace mongo { const std::string IdentityNS("local.me"); const BSONField HostField("host"); /** * A very simple mock that acts like a database server. Every object keeps track of its own * InstanceID, which initially starts at zero and increments every time it is restarted. * This is primarily used for simulating the state of which old connections won't be able * to talk to the sockets that has already been closed on this server. * * Note: All operations on this server are protected by a lock. */ class MockRemoteDBServer { public: typedef size_t InstanceID; /** * Creates a new mock server. This can also be setup to work with the * ConnectionString class by using mongo::MockConnRegistry as follows: * * ConnectionString::setConnectionHook(MockConnRegistry::get()->getConnStrHook()); * MockRemoteDBServer server("$a:27017"); * MockConnRegistry::get()->addServer(&server); * * This allows clients using the ConnectionString::connect interface to create * connections to this server. The requirements to make this hook fully functional are: * * 1. hostAndPort of this server should start with $. * 2. No other instance has the same hostAndPort as this. * * This server will also contain the hostAndPort inside the IdentityNS * collection. This is convenient for testing query routing. * * @param hostAndPort the host name with port for this server. * * @see MockConnRegistry */ MockRemoteDBServer(const std::string& hostAndPort); virtual ~MockRemoteDBServer(); // // Connectivity methods // /** * Set a delay for calls to query and runCommand */ void setDelay(long long milliSec); /** * Shuts down this server. Any operations on this server with an InstanceID * less than or equal to the current one will throw a mongo::SocketException. * To bring the server up again, use the reboot method. */ void shutdown(); /** * Increments the instanceID of this server. */ void reboot(); /** * @return true if this server is running */ bool isRunning() const; // // Mocking methods // /** * Sets the reply for a command. * * @param cmdName the name of the command * @param replyObj the exact reply for the command */ void setCommandReply(const std::string& cmdName, const mongo::BSONObj& replyObj); /** * Sets the reply for a command. * * @param cmdName the name of the command. * @param replySequence the sequence of replies to cycle through every time * the given command is requested. This is useful for setting up a * sequence of response when the command can be called more than once * that requires different results when calling a method. */ void setCommandReply(const std::string& cmdName, const std::vector& replySequence); /** * Inserts a single document to this server. * * @param ns the namespace to insert the document to. * @param obj the document to insert. * @param flags ignored. */ void insert(const std::string& ns, BSONObj obj, int flags = 0); /** * Removes documents from this server. * * @param ns the namespace to remove documents from. * @param query ignored. * @param flags ignored. */ void remove(const std::string& ns, Query query, int flags = 0); // // DBClientBase methods // bool runCommand(InstanceID id, const std::string& dbname, const mongo::BSONObj& cmdObj, mongo::BSONObj& info, int options = 0); mongo::BSONArray query(InstanceID id, const std::string& ns, mongo::Query query = mongo::Query(), int nToReturn = 0, int nToSkip = 0, const mongo::BSONObj* fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); // // Getters // InstanceID getInstanceID() const; mongo::ConnectionString::ConnectionType type() const; double getSoTimeout() const; /** * @return the exact string address passed to hostAndPort parameter of the * constructor. In other words, doesn't automatically append a * 'default' port if none is specified. */ std::string getServerAddress() const; std::string toString(); // // Call counters // size_t getCmdCount() const; size_t getQueryCount() const; void clearCounters(); private: /** * A very simple class for cycling through a set of BSONObj */ class CircularBSONIterator { public: /** * Creates a new iterator with a deep copy of the vector. */ CircularBSONIterator(const std::vector& replyVector); mongo::BSONObj next(); private: std::vector::iterator _iter; std::vector _replyObjs; }; /** * Checks whether the instance of the server is still up. * * @throws mongo::SocketException if this server is down */ void checkIfUp(InstanceID id) const; typedef unordered_map > CmdToReplyObj; typedef unordered_map > MockDataMgr; bool _isRunning; const std::string _hostAndPort; long long _delayMilliSec; // // Mock replies // CmdToReplyObj _cmdMap; MockDataMgr _dataMgr; // // Op Counters // size_t _cmdCount; size_t _queryCount; // Unique id for every restart of this server used for rejecting requests from // connections that are still "connected" to the old instance InstanceID _instanceID; // protects this entire instance mutable boost::mutex _lock; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_replica_set.cpp000066400000000000000000000225111273231111400264770ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/db/repl/member_state.h" #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/util/map_util.h" #include using namespace mongo::repl; namespace mongo { using std::string; using std::map; using std::vector; MockReplicaSet::MockReplicaSet(const string& setName, size_t nodes) : _setName(setName) { ReplConfigMap replConfig; for (size_t n = 0; n < nodes; n++) { std::stringstream str; str << "$" << setName << n << ":27017"; const string hostName(str.str()); if (n == 0) { _primaryHost = hostName; } MockRemoteDBServer* mockServer = new MockRemoteDBServer(hostName); _nodeMap[hostName] = mockServer; MockConnRegistry::get()->addServer(mockServer); ReplSetConfig::MemberCfg config; config.h = HostAndPort(hostName); replConfig.insert(std::make_pair(hostName, config)); } setConfig(replConfig); } MockReplicaSet::~MockReplicaSet() { for (ReplNodeMap::iterator iter = _nodeMap.begin(); iter != _nodeMap.end(); ++iter) { MockConnRegistry::get()->removeServer(iter->second->getServerAddress()); delete iter->second; } } string MockReplicaSet::getSetName() const { return _setName; } string MockReplicaSet::getConnectionString() const { std::stringstream str; str << _setName; str << "/"; ReplNodeMap::const_iterator iter = _nodeMap.begin(); while (iter != _nodeMap.end()) { str << iter->second->getServerAddress(); ++iter; if (iter != _nodeMap.end()) { str << ","; } } return str.str(); } vector MockReplicaSet::getHosts() const { vector list; for (ReplNodeMap::const_iterator iter = _nodeMap.begin(); iter != _nodeMap.end(); ++iter) { list.push_back(HostAndPort(iter->second->getServerAddress())); } return list; } string MockReplicaSet::getPrimary() const { return _primaryHost; } void MockReplicaSet::setPrimary(const string& hostAndPort) { ReplConfigMap::const_iterator iter = _replConfig.find(hostAndPort); fassert(16578, iter != _replConfig.end()); const ReplSetConfig::MemberCfg& config = iter->second; fassert(16579, !config.hidden && config.priority > 0 && !config.arbiterOnly); _primaryHost = hostAndPort; mockIsMasterCmd(); mockReplSetGetStatusCmd(); } vector MockReplicaSet::getSecondaries() const { vector secondaries; for (ReplConfigMap::const_iterator iter = _replConfig.begin(); iter != _replConfig.end(); ++iter) { if (iter->first != _primaryHost) { secondaries.push_back(iter->first); } } return secondaries; } MockRemoteDBServer* MockReplicaSet::getNode(const string& hostAndPort) { return mapFindWithDefault(_nodeMap, hostAndPort, static_cast(NULL)); } MockReplicaSet::ReplConfigMap MockReplicaSet::getReplConfig() const { return _replConfig; } void MockReplicaSet::setConfig(const MockReplicaSet::ReplConfigMap& newConfig) { _replConfig = newConfig; mockIsMasterCmd(); mockReplSetGetStatusCmd(); } void MockReplicaSet::kill(const string& hostAndPort) { verify(_nodeMap.count(hostAndPort) == 1); _nodeMap[hostAndPort]->shutdown(); } void MockReplicaSet::kill(const vector& hostList) { for (vector::const_iterator iter = hostList.begin(); iter != hostList.end(); ++iter) { kill(*iter); } } void MockReplicaSet::restore(const string& hostAndPort) { verify(_nodeMap.count(hostAndPort) == 1); _nodeMap[hostAndPort]->reboot(); } void MockReplicaSet::mockIsMasterCmd() { // Copied from ReplSetImpl::_fillIsMaster for (ReplNodeMap::iterator nodeIter = _nodeMap.begin(); nodeIter != _nodeMap.end(); ++nodeIter) { const string& hostAndPort = nodeIter->first; BSONObjBuilder builder; builder.append("setName", _setName); ReplConfigMap::const_iterator configIter = _replConfig.find(hostAndPort); if (configIter == _replConfig.end()) { builder.append("ismaster", false); builder.append("secondary", false); vector hostList; builder.append("hosts", hostList); } else { const bool isPrimary = hostAndPort == getPrimary(); builder.append("ismaster", isPrimary); builder.append("secondary", !isPrimary); { // TODO: add passives & arbiters vector hostList; hostList.push_back(getPrimary()); const vector secondaries = getSecondaries(); for (vector::const_iterator secIter = secondaries.begin(); secIter != secondaries.end(); ++secIter) { hostList.push_back(*secIter); } builder.append("hosts", hostList); } builder.append("primary", getPrimary()); const ReplSetConfig::MemberCfg& replConfig = configIter->second; if (replConfig.arbiterOnly) { builder.append("arbiterOnly", true); } if (replConfig.priority == 0 && !replConfig.arbiterOnly) { builder.append("passive", true); } if (replConfig.slaveDelay) { builder.append("slaveDelay", replConfig.slaveDelay); } if (replConfig.hidden) { builder.append("hidden", true); } if (!replConfig.buildIndexes) { builder.append("buildIndexes", false); } if (!replConfig.tags.empty()) { BSONObjBuilder tagBuilder; for (map::const_iterator tagIter = replConfig.tags.begin(); tagIter != replConfig.tags.end(); tagIter++) { tagBuilder.append(tagIter->first, tagIter->second); } builder.append("tags", tagBuilder.done()); } } builder.append("me", hostAndPort); builder.append("ok", true); nodeIter->second->setCommandReply("ismaster", builder.done()); } } int MockReplicaSet::getState(const std::string& hostAndPort) const { if (_replConfig.count(hostAndPort) < 1) { return static_cast(MemberState::RS_REMOVED); } else if (hostAndPort == getPrimary()) { return static_cast(MemberState::RS_PRIMARY); } else { return static_cast(MemberState::RS_SECONDARY); } } void MockReplicaSet::mockReplSetGetStatusCmd() { // Copied from ReplSetImpl::_summarizeStatus for (ReplNodeMap::iterator nodeIter = _nodeMap.begin(); nodeIter != _nodeMap.end(); ++nodeIter) { MockRemoteDBServer* node = nodeIter->second; vector hostsField; BSONObjBuilder fullStatBuilder; { BSONObjBuilder selfStatBuilder; selfStatBuilder.append("name", node->getServerAddress()); selfStatBuilder.append("health", 1.0); selfStatBuilder.append("state", getState(node->getServerAddress())); selfStatBuilder.append("self", true); // TODO: _id, stateStr, uptime, optime, optimeDate, maintenanceMode, errmsg hostsField.push_back(selfStatBuilder.obj()); } for (ReplConfigMap::const_iterator replConfIter = _replConfig.begin(); replConfIter != _replConfig.end(); ++replConfIter) { MockRemoteDBServer* hostNode = getNode(replConfIter->first); if (hostNode == node) { continue; } BSONObjBuilder hostMemberBuilder; // TODO: _id, stateStr, uptime, optime, optimeDate, lastHeartbeat, pingMs // errmsg, authenticated hostMemberBuilder.append("name", hostNode->getServerAddress()); const double health = hostNode->isRunning() ? 1.0 : 0.0; hostMemberBuilder.append("health", health); hostMemberBuilder.append("state", getState(hostNode->getServerAddress())); hostsField.push_back(hostMemberBuilder.obj()); } sort(hostsField.begin(), hostsField.end()); // TODO: syncingTo fullStatBuilder.append("set", _setName); fullStatBuilder.appendTimeT("date", time(0)); fullStatBuilder.append("myState", getState(node->getServerAddress())); fullStatBuilder.append("members", hostsField); fullStatBuilder.append("ok", true); node->setCommandReply("replSetGetStatus", fullStatBuilder.done()); } } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock/mock_replica_set.h000066400000000000000000000105201273231111400261410ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/dbtests/mock/mock_remote_db_server.h" //#include "mongo/db/repl/rs_config.h" #include #include #include namespace mongo { namespace repl { class ReplSetConfig { public: struct MemberCfg { MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(false), slaveDelay(0), hidden(false), buildIndexes(true) {} int _id; unsigned votes; HostAndPort h; double priority; bool arbiterOnly; int slaveDelay; bool hidden; bool buildIndexes; std::map tags; }; }; } // namespace repl /** * This is a helper class for managing a replica set consisting of * MockRemoteDBServer instances. * * Note: Be sure to call ScopedDbConnection::clearPool() after every test * when doing tests that involves the ReplicaSetMonitor. This is because * it uses ScopedDbConnection which means you can have a residue connections * that was created from previous tests and can cause a seg fault if the * MockRemoteDBServer instances were already destroyed. * * Warning: Not thread-safe */ class MockReplicaSet { public: typedef std::map ReplConfigMap; /** * Creates a mock replica set and automatically mocks the isMaster * and replSetGetStatus commands based on the default replica set * configuration. * * @param setName The name for this replica set * @param nodes The initial number of nodes for this replica set */ MockReplicaSet(const std::string& setName, size_t nodes); ~MockReplicaSet(); // // getters // std::string getSetName() const; std::string getConnectionString() const; std::vector getHosts() const; ReplConfigMap getReplConfig() const; std::string getPrimary() const; std::vector getSecondaries() const; /** * Sets the configuration for this replica sets. This also has a side effect * of mocking the ismaster and replSetGetStatus command responses based on * the new config. * * Note: does not automatically select a new primary. Can be done manually by * calling setPrimary. */ void setConfig(const ReplConfigMap& newConfig); void setPrimary(const std::string& hostAndPort); /** * @return pointer to the mocked remote server with the given hostName. * NULL if host doesn't exists. */ MockRemoteDBServer* getNode(const std::string& hostAndPort); /** * Kills a node belonging to this set. * * @param hostName the name of the replica node to kill. */ void kill(const std::string& hostAndPort); /** * Kills a set of host belonging to this set. * * @param hostList the list of host names of the servers to kill. */ void kill(const std::vector& hostList); /** * Reboots a node. * * @param hostName the name of the host to reboot. */ void restore(const std::string& hostName); private: typedef std::map ReplNodeMap; /** * Mocks the ismaster command based on the information on the current * replica set configuration. */ void mockIsMasterCmd(); /** * Mocks the replSetGetStatus command based on the current states of the * mocked servers. */ void mockReplSetGetStatusCmd(); /** * @return the replica set state of the given host */ int getState(const std::string& hostAndPort) const; const std::string _setName; ReplNodeMap _nodeMap; ReplConfigMap _replConfig; std::string _primaryHost; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock_dbclient_conn_test.cpp000066400000000000000000000432601273231111400271200ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This file includes integration testing between the MockDBClientBase and MockRemoteDB. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientinterface.h" #include "mongo/db/jsobj.h" #include "mongo/dbtests/mock/mock_dbclient_connection.h" #include "mongo/unittest/unittest.h" #include "mongo/util/timer.h" #include #include #include #include using mongo::BSONObj; using mongo::ConnectionString; using mongo::MockDBClientConnection; using mongo::MockRemoteDBServer; using mongo::Query; using std::string; using std::vector; namespace mongo_test { TEST(MockDBClientConnTest, ServerAddress) { MockRemoteDBServer server("test"); MockDBClientConnection conn(&server); ASSERT_EQUALS("test", conn.getServerAddress()); ASSERT_EQUALS("test", conn.toString()); } TEST(MockDBClientConnTest, QueryCount) { MockRemoteDBServer server("test"); { MockDBClientConnection conn(&server); ASSERT_EQUALS(0U, server.getQueryCount()); conn.query("foo.bar"); } ASSERT_EQUALS(1U, server.getQueryCount()); { MockDBClientConnection conn(&server); conn.query("foo.bar"); ASSERT_EQUALS(2U, server.getQueryCount()); } } TEST(MockDBClientConnTest, InsertAndQuery) { MockRemoteDBServer server("test"); const string ns("test.user"); { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(!cursor->more()); server.insert(ns, BSON("x" << 1)); server.insert(ns, BSON("y" << 2)); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["x"].numberInt()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS(2, secondDoc["y"].numberInt()); ASSERT(!cursor->more()); } // Make sure that repeated calls will still give you the same result { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["x"].numberInt()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS(2, secondDoc["y"].numberInt()); ASSERT(!cursor->more()); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns, mongo::Query(), 1); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["x"].numberInt()); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, InsertAndQueryTwice) { MockRemoteDBServer server("test"); const string ns("test.user"); server.insert(ns, BSON("x" << 1)); { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["x"].numberInt()); } server.insert(ns, BSON("y" << 2)); { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["x"].numberInt()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS(2, secondDoc["y"].numberInt()); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, QueryWithNoResults) { MockRemoteDBServer server("test"); const string ns("test.user"); server.insert(ns, BSON("x" << 1)); MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query("other.ns"); ASSERT(!cursor->more()); } TEST(MockDBClientConnTest, MultiNSInsertAndQuery) { MockRemoteDBServer server("test"); const string ns1("test.user"); const string ns2("foo.bar"); const string ns3("mongo.db"); { MockDBClientConnection conn(&server); conn.insert(ns1, BSON("a" << 1)); conn.insert(ns2, BSON("ef" << "gh")); conn.insert(ns3, BSON("x" << 2)); conn.insert(ns1, BSON("b" << 3)); conn.insert(ns2, BSON("jk" << "lm")); conn.insert(ns2, BSON("x" << "yz")); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns1); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["a"].numberInt()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS(3, secondDoc["b"].numberInt()); ASSERT(!cursor->more()); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns2); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS("gh", firstDoc["ef"].String()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS("lm", secondDoc["jk"].String()); ASSERT(cursor->more()); BSONObj thirdDoc = cursor->next(); ASSERT_EQUALS("yz", thirdDoc["x"].String()); ASSERT(!cursor->more()); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns3); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(2, firstDoc["x"].numberInt()); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, SimpleRemove) { MockRemoteDBServer server("test"); const string ns("test.user"); { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(!cursor->more()); conn.insert(ns, BSON("x" << 1)); conn.insert(ns, BSON("y" << 1)); } { MockDBClientConnection conn(&server); conn.remove(ns, Query(), false); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(!cursor->more()); } // Make sure that repeated calls will still give you the same result { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, MultiNSRemove) { MockRemoteDBServer server("test"); const string ns1("test.user"); const string ns2("foo.bar"); const string ns3("mongo.db"); { MockDBClientConnection conn(&server); conn.insert(ns1, BSON("a" << 1)); conn.insert(ns2, BSON("ef" << "gh")); conn.insert(ns3, BSON("x" << 2)); conn.insert(ns1, BSON("b" << 3)); conn.insert(ns2, BSON("jk" << "lm")); conn.insert(ns2, BSON("x" << "yz")); } { MockDBClientConnection conn(&server); conn.remove(ns2, Query(), false); std::auto_ptr cursor = conn.query(ns2); ASSERT(!cursor->more()); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns1); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(1, firstDoc["a"].numberInt()); ASSERT(cursor->more()); BSONObj secondDoc = cursor->next(); ASSERT_EQUALS(3, secondDoc["b"].numberInt()); ASSERT(!cursor->more()); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns3); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(2, firstDoc["x"].numberInt()); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, InsertAfterRemove) { MockRemoteDBServer server("test"); const string ns("test.user"); { MockDBClientConnection conn(&server); conn.insert(ns, BSON("a" << 1)); conn.insert(ns, BSON("b" << 3)); conn.insert(ns, BSON("x" << "yz")); } { MockDBClientConnection conn(&server); conn.remove(ns, Query(), false); } { MockDBClientConnection conn(&server); conn.insert(ns, BSON("x" << 100)); } { MockDBClientConnection conn(&server); std::auto_ptr cursor = conn.query(ns); ASSERT(cursor->more()); BSONObj firstDoc = cursor->next(); ASSERT_EQUALS(100, firstDoc["x"].numberInt()); ASSERT(!cursor->more()); } } TEST(MockDBClientConnTest, SetCmdReply) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 1 << "host" << "local")); { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.bar", BSON("serverStatus" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("local", response["host"].str()); ASSERT_EQUALS(1U, server.getCmdCount()); } // Make sure that repeated calls will still give you the same result { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.bar", BSON("serverStatus" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("local", response["host"].str()); ASSERT_EQUALS(2U, server.getCmdCount()); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.bar", BSON("serverStatus" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("local", response["host"].str()); ASSERT_EQUALS(3U, server.getCmdCount()); } } TEST(MockDBClientConnTest, CyclingCmd) { MockRemoteDBServer server("test"); { vector isMasterSequence; isMasterSequence.push_back(BSON("set" << "a" << "isMaster" << true << "ok" << 1)); isMasterSequence.push_back(BSON("set" << "a" << "isMaster" << false << "ok" << 1)); server.setCommandReply("isMaster", isMasterSequence); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); ASSERT(response["isMaster"].trueValue()); ASSERT_EQUALS(1U, server.getCmdCount()); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); ASSERT(!response["isMaster"].trueValue()); ASSERT_EQUALS(2U, server.getCmdCount()); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << 1), response)); ASSERT_EQUALS(1, response["ok"].numberInt()); ASSERT_EQUALS("a", response["set"].str()); ASSERT(response["isMaster"].trueValue()); ASSERT_EQUALS(3U, server.getCmdCount()); } } TEST(MockDBClientConnTest, CmdWithMultiFields) { MockRemoteDBServer server("test"); server.setCommandReply("getLastError", BSON("ok" << 1 << "n" << 10)); MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand( "foo.baz", BSON("getLastError" << 1 << "w" << 2 << "journal" << true), response)); ASSERT_EQUALS(10, response["n"].numberInt()); } TEST(MockDBClientConnTest, BadCmd) { MockRemoteDBServer server("test"); server.setCommandReply("getLastError", BSON("ok" << 0)); MockDBClientConnection conn(&server); BSONObj response; ASSERT(!conn.runCommand("foo.baz", BSON("getLastError" << 1), response)); } TEST(MockDBClientConnTest, MultipleStoredResponse) { MockRemoteDBServer server("test"); server.setCommandReply("getLastError", BSON("ok" << 1 << "n" << 10)); server.setCommandReply("isMaster", BSON("ok" << 1 << "secondary" << false)); MockDBClientConnection conn(&server); { BSONObj response; ASSERT(conn.runCommand("foo.baz", BSON("isMaster" << "abc"), response)); ASSERT(!response["secondary"].trueValue()); } { BSONObj response; ASSERT(conn.runCommand("a.b", BSON("getLastError" << 1), response)); ASSERT_EQUALS(10, response["n"].numberInt()); } } TEST(MockDBClientConnTest, CmdCount) { MockRemoteDBServer server("test"); ASSERT_EQUALS(0U, server.getCmdCount()); server.setCommandReply("serverStatus", BSON("ok" << 1)); { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("foo.bar", BSON("serverStatus" << 1), response)); ASSERT_EQUALS(1U, server.getCmdCount()); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT(conn.runCommand("baz.bar", BSON("serverStatus" << 1), response)); ASSERT_EQUALS(2U, server.getCmdCount()); } } TEST(MockDBClientConnTest, Shutdown) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 1)); ASSERT(server.isRunning()); { MockDBClientConnection conn(&server); server.shutdown(); ASSERT(!server.isRunning()); ASSERT_THROWS(conn.query("test.user"), mongo::SocketException); } { MockDBClientConnection conn(&server); BSONObj response; ASSERT_THROWS(conn.runCommand("test.user", BSON("serverStatus" << 1), response), mongo::SocketException); } ASSERT_EQUALS(0U, server.getQueryCount()); ASSERT_EQUALS(0U, server.getCmdCount()); } TEST(MockDBClientConnTest, Restart) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 1)); MockDBClientConnection conn1(&server); // Do some queries and commands then check the counters later that // new instance still has it conn1.query("test.user"); BSONObj response; conn1.runCommand("test.user", BSON("serverStatus" << 1), response); server.shutdown(); ASSERT_THROWS(conn1.query("test.user"), mongo::SocketException); // New connections shouldn't work either MockDBClientConnection conn2(&server); ASSERT_THROWS(conn2.query("test.user"), mongo::SocketException); ASSERT_EQUALS(1U, server.getQueryCount()); ASSERT_EQUALS(1U, server.getCmdCount()); server.reboot(); ASSERT(server.isRunning()); { MockDBClientConnection conn(&server); conn.query("test.user"); } // Old connections still shouldn't work ASSERT_THROWS(conn1.query("test.user"), mongo::SocketException); ASSERT_THROWS(conn2.query("test.user"), mongo::SocketException); ASSERT_EQUALS(2U, server.getQueryCount()); ASSERT_EQUALS(1U, server.getCmdCount()); } TEST(MockDBClientConnTest, ClearCounter) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 1)); MockDBClientConnection conn(&server); conn.query("test.user"); BSONObj response; conn.runCommand("test.user", BSON("serverStatus" << 1), response); server.clearCounters(); ASSERT_EQUALS(0U, server.getQueryCount()); ASSERT_EQUALS(0U, server.getCmdCount()); } TEST(MockDBClientConnTest, Delay) { MockRemoteDBServer server("test"); server.setCommandReply("serverStatus", BSON("ok" << 1)); server.setDelay(150); MockDBClientConnection conn(&server); { mongo::Timer timer; conn.query("x.x"); const int nowInMilliSec = timer.millis(); // Use a more lenient lower bound since some platforms like Windows // don't guarantee that sleeps will not wake up earlier (unlike // nanosleep we use for Linux) ASSERT_GREATER_THAN_OR_EQUALS(nowInMilliSec, 130); } { mongo::Timer timer; BSONObj response; conn.runCommand("x.x", BSON("serverStatus" << 1), response); const int nowInMilliSec = timer.millis(); ASSERT_GREATER_THAN_OR_EQUALS(nowInMilliSec, 130); } ASSERT_EQUALS(1U, server.getQueryCount()); ASSERT_EQUALS(1U, server.getCmdCount()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/mock_replica_set_test.cpp000066400000000000000000000314651273231111400266150ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientinterface.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" #include #include using mongo::BSONElement; using mongo::BSONObj; using mongo::BSONObjIterator; using mongo::ConnectionString; using mongo::MockRemoteDBServer; using mongo::MockReplicaSet; using std::set; using std::string; using std::vector; namespace mongo_test { TEST(MockReplicaSetTest, SetName) { MockReplicaSet replSet("n", 3); ASSERT_EQUALS("n", replSet.getSetName()); } TEST(MockReplicaSetTest, ConnectionString) { MockReplicaSet replSet("n", 3); ASSERT_EQUALS("n/$n0:27017,$n1:27017,$n2:27017", replSet.getConnectionString()); } TEST(MockReplicaSetTest, GetNode) { MockReplicaSet replSet("n", 3); ASSERT_EQUALS("$n0:27017", replSet.getNode("$n0:27017")->getServerAddress()); ASSERT_EQUALS("$n1:27017", replSet.getNode("$n1:27017")->getServerAddress()); ASSERT_EQUALS("$n2:27017", replSet.getNode("$n2:27017")->getServerAddress()); ASSERT(replSet.getNode("$n3:27017") == NULL); } TEST(MockReplicaSetTest, IsMasterNode0) { MockReplicaSet replSet("n", 3); set expectedHosts; expectedHosts.insert("$n0:27017"); expectedHosts.insert("$n1:27017"); expectedHosts.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n0:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); ASSERT(cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n0:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); set hostList; BSONObjIterator iter(cmdResponse["hosts"].embeddedObject()); while (iter.more()) { hostList.insert(iter.next().str()); } ASSERT(expectedHosts == hostList); } TEST(MockReplicaSetTest, IsMasterNode1) { MockReplicaSet replSet("n", 3); set expectedHosts; expectedHosts.insert("$n0:27017"); expectedHosts.insert("$n1:27017"); expectedHosts.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n1:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n1:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); set hostList; BSONObjIterator iter(cmdResponse["hosts"].embeddedObject()); while (iter.more()) { hostList.insert(iter.next().str()); } ASSERT(expectedHosts == hostList); } TEST(MockReplicaSetTest, IsMasterNode2) { MockReplicaSet replSet("n", 3); set expectedHosts; expectedHosts.insert("$n0:27017"); expectedHosts.insert("$n1:27017"); expectedHosts.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n2:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n2:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); set hostList; BSONObjIterator iter(cmdResponse["hosts"].embeddedObject()); while (iter.more()) { hostList.insert(iter.next().str()); } ASSERT(expectedHosts == hostList); } TEST(MockReplicaSetTest, ReplSetGetStatusNode0) { MockReplicaSet replSet("n", 3); set expectedMembers; expectedMembers.insert("$n0:27017"); expectedMembers.insert("$n1:27017"); expectedMembers.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n0:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("replSetGetStatus" << 1), cmdResponse); ASSERT(ok); ASSERT_EQUALS("n", cmdResponse["set"].str()); ASSERT_EQUALS(1, cmdResponse["myState"].numberInt()); set memberList; BSONObjIterator iter(cmdResponse["members"].embeddedObject()); while (iter.more()) { BSONElement member(iter.next()); memberList.insert(member["name"].str()); if (member["self"].trueValue()) { ASSERT_EQUALS(1, member["state"].numberInt()); ASSERT_EQUALS("$n0:27017", member["name"].str()); } else { ASSERT_EQUALS(2, member["state"].numberInt()); } } ASSERT(expectedMembers == memberList); } TEST(MockReplicaSetTest, ReplSetGetStatusNode1) { MockReplicaSet replSet("n", 3); set expectedMembers; expectedMembers.insert("$n0:27017"); expectedMembers.insert("$n1:27017"); expectedMembers.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n1:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("replSetGetStatus" << 1), cmdResponse); ASSERT(ok); ASSERT_EQUALS("n", cmdResponse["set"].str()); ASSERT_EQUALS(2, cmdResponse["myState"].numberInt()); set memberList; BSONObjIterator iter(cmdResponse["members"].embeddedObject()); while (iter.more()) { BSONElement member(iter.next()); memberList.insert(member["name"].str()); if (member["self"].trueValue()) { ASSERT_EQUALS(2, member["state"].numberInt()); ASSERT_EQUALS("$n1:27017", member["name"].str()); } else if (member["name"].str() == "$n0:27017") { ASSERT_EQUALS(1, member["state"].numberInt()); } else { ASSERT_EQUALS(2, member["state"].numberInt()); } } ASSERT(expectedMembers == memberList); } TEST(MockReplicaSetTest, ReplSetGetStatusNode2) { MockReplicaSet replSet("n", 3); set expectedMembers; expectedMembers.insert("$n0:27017"); expectedMembers.insert("$n1:27017"); expectedMembers.insert("$n2:27017"); BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n2:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("replSetGetStatus" << 1), cmdResponse); ASSERT(ok); ASSERT_EQUALS("n", cmdResponse["set"].str()); ASSERT_EQUALS(2, cmdResponse["myState"].numberInt()); set memberList; BSONObjIterator iter(cmdResponse["members"].embeddedObject()); while (iter.more()) { BSONElement member(iter.next()); memberList.insert(member["name"].str()); if (member["self"].trueValue()) { ASSERT_EQUALS(2, member["state"].numberInt()); ASSERT_EQUALS("$n2:27017", member["name"].str()); } else if (member["name"].str() == "$n0:27017") { ASSERT_EQUALS(1, member["state"].numberInt()); } else { ASSERT_EQUALS(2, member["state"].numberInt()); } } ASSERT(expectedMembers == memberList); } TEST(MockReplicaSetTest, IsMasterReconfigNodeRemoved) { MockReplicaSet replSet("n", 3); MockReplicaSet::ReplConfigMap config = replSet.getReplConfig(); const string hostToRemove("$n1:27017"); config.erase(hostToRemove); replSet.setConfig(config); { // Check isMaster for node still in set BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n0:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); ASSERT(cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS("$n0:27017", cmdResponse["me"].str()); ASSERT_EQUALS("$n0:27017", cmdResponse["primary"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); set expectedHosts; expectedHosts.insert("$n0:27017"); expectedHosts.insert("$n2:27017"); set hostList; BSONObjIterator iter(cmdResponse["hosts"].embeddedObject()); while (iter.more()) { hostList.insert(iter.next().str()); } ASSERT(expectedHosts == hostList); ASSERT(hostList.count(hostToRemove) == 0); } { // Check isMaster for node still not in set anymore BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode(hostToRemove); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("ismaster" << 1), cmdResponse); ASSERT(ok); ASSERT(!cmdResponse["ismaster"].trueValue()); ASSERT(!cmdResponse["secondary"].trueValue()); ASSERT_EQUALS(hostToRemove, cmdResponse["me"].str()); ASSERT_EQUALS("n", cmdResponse["setName"].str()); } } TEST(MockReplicaSetTest, replSetGetStatusReconfigNodeRemoved) { MockReplicaSet replSet("n", 3); MockReplicaSet::ReplConfigMap config = replSet.getReplConfig(); const string hostToRemove("$n1:27017"); config.erase(hostToRemove); replSet.setConfig(config); { // Check replSetGetStatus for node still in set BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode("$n2:27017"); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("replSetGetStatus" << 1), cmdResponse); ASSERT(ok); ASSERT_EQUALS("n", cmdResponse["set"].str()); ASSERT_EQUALS(2, cmdResponse["myState"].numberInt()); set memberList; BSONObjIterator iter(cmdResponse["members"].embeddedObject()); while (iter.more()) { BSONElement member(iter.next()); memberList.insert(member["name"].str()); if (member["self"].trueValue()) { ASSERT_EQUALS(2, member["state"].numberInt()); ASSERT_EQUALS("$n2:27017", member["name"].str()); } else if (member["name"].str() == "$n0:27017") { ASSERT_EQUALS(1, member["state"].numberInt()); } else { ASSERT_EQUALS(2, member["state"].numberInt()); } } set expectedMembers; expectedMembers.insert("$n0:27017"); expectedMembers.insert("$n2:27017"); ASSERT(expectedMembers == memberList); } { // Check replSetGetStatus for node still not in set anymore BSONObj cmdResponse; MockRemoteDBServer* node = replSet.getNode(hostToRemove); const MockRemoteDBServer::InstanceID id = node->getInstanceID(); bool ok = node->runCommand(id, "foo.bar", BSON("replSetGetStatus" << 1), cmdResponse); ASSERT(ok); ASSERT_EQUALS("n", cmdResponse["set"].str()); ASSERT_EQUALS(10, cmdResponse["myState"].numberInt()); } } TEST(MockReplicaSetTest, KillNode) { MockReplicaSet replSet("n", 3); const string priHostName(replSet.getPrimary()); replSet.kill(priHostName); ASSERT(!replSet.getNode(priHostName)->isRunning()); const vector secondaries = replSet.getSecondaries(); for (vector::const_iterator iter = secondaries.begin(); iter != secondaries.end(); ++iter) { ASSERT(replSet.getNode(*iter)->isRunning()); } } TEST(MockReplicaSetTest, KillMultipleNode) { MockReplicaSet replSet("n", 3); const vector secondaries = replSet.getSecondaries(); replSet.kill(replSet.getSecondaries()); for (vector::const_iterator iter = secondaries.begin(); iter != secondaries.end(); ++iter) { ASSERT(!replSet.getNode(*iter)->isRunning()); } const string priHostName(replSet.getPrimary()); ASSERT(replSet.getNode(priHostName)->isRunning()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/dbtests/replica_set_monitor_test.cpp000066400000000000000000001417321273231111400273520ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclient_rs.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/client/replica_set_monitor_internal.h" #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" #include #include using std::map; using std::vector; using std::set; using std::string; using boost::scoped_ptr; using mongo::BSONObj; using mongo::BSONObjBuilder; using mongo::BSONArray; using mongo::BSONArrayBuilder; using mongo::BSONElement; using mongo::ConnectionString; using mongo::HostAndPort; using mongo::MockReplicaSet; using mongo::ReadPreference; using mongo::ReadPreferenceSetting; using mongo::ReplicaSetMonitor; using mongo::ReplicaSetMonitorPtr; using mongo::TagSet; // Pull nested types to top-level scope typedef ReplicaSetMonitor::IsMasterReply IsMasterReply; typedef ReplicaSetMonitor::ScanState ScanState; typedef ReplicaSetMonitor::ScanStatePtr ScanStatePtr; typedef ReplicaSetMonitor::SetState SetState; typedef ReplicaSetMonitor::SetStatePtr SetStatePtr; typedef ReplicaSetMonitor::Refresher Refresher; typedef Refresher::NextStep NextStep; typedef ScanState::UnconfirmedReplies UnconfirmedReplies; typedef SetState::Node Node; typedef SetState::Nodes Nodes; namespace mongo_test { bool isCompatible(const Node& node, ReadPreference pref, const TagSet& tagSet) { set seeds; seeds.insert(node.host); SetState set("name", seeds); set.nodes.push_back(node); ReadPreferenceSetting criteria(pref, tagSet); return !set.getMatchingHost(criteria).empty(); } HostAndPort selectNode(const vector& nodes, ReadPreference pref, const TagSet& tagSet, int latencyThresholdMillis, bool* isPrimarySelected) { invariant(!nodes.empty()); set seeds; seeds.insert(nodes.front().host); SetState set("name", seeds); set.nodes = nodes; set.latencyThresholdMicros = latencyThresholdMillis * 1000; ReadPreferenceSetting criteria(pref, tagSet); HostAndPort out = set.getMatchingHost(criteria); if (isPrimarySelected) *isPrimarySelected = !out.empty() && set.findNode(out)->isMaster; return out; } const BSONObj SampleIsMasterDoc = BSON("tags" << BSON("dc" << "NYC" << "p" << "2" << "region" << "NA")); const BSONObj SampleTags = SampleIsMasterDoc["tags"].Obj(); const BSONObj NoTags = BSONObj(); const BSONObj NoTagIsMasterDoc = BSON("isMaster" << true); TEST(ReplSetMonitorNode, SimpleGoodMatch) { Node node(((HostAndPort()))); node.tags = BSON("dc" << "sf"); ASSERT(node.matches(BSON("dc" << "sf"))); } TEST(ReplSetMonitorNode, SimpleBadMatch) { Node node((HostAndPort())); node.tags = BSON("dc" << "nyc"); ASSERT(!node.matches(BSON("dc" << "sf"))); } TEST(ReplSetMonitorNode, ExactMatch) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(node.matches(SampleIsMasterDoc["tags"].Obj())); } TEST(ReplSetMonitorNode, EmptyTag) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(node.matches(BSONObj())); } TEST(ReplSetMonitorNode, MemberNoTagMatchesEmptyTag) { Node node((HostAndPort())); node.tags = NoTags; ASSERT(node.matches(BSONObj())); } TEST(ReplSetMonitorNode, MemberNoTagDoesNotMatch) { Node node((HostAndPort())); node.tags = NoTags; ASSERT(!node.matches(BSON("dc" << "NYC"))); } TEST(ReplSetMonitorNode, IncompleteMatch) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(!node.matches(BSON("dc" << "NYC" << "p" << "2" << "hello" << "world"))); } TEST(ReplSetMonitorNode, PartialMatch) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(node.matches(BSON("dc" << "NYC" << "p" << "2"))); } TEST(ReplSetMonitorNode, SingleTagCrit) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(node.matches(BSON("p" << "2"))); } TEST(ReplSetMonitorNode, BadSingleTagCrit) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(!node.matches(BSON("dc" << "SF"))); } TEST(ReplSetMonitorNode, NonExistingFieldTag) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(!node.matches(BSON("noSQL" << "Mongo"))); } TEST(ReplSetMonitorNode, UnorederedMatching) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(node.matches(BSON("p" << "2" << "dc" << "NYC"))); } TEST(ReplSetMonitorNode, SameValueDiffKey) { Node node((HostAndPort())); node.tags = SampleTags; ASSERT(!node.matches(BSON("datacenter" << "NYC"))); } TEST(ReplSetMonitorNode, PriNodeCompatibleTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = true; BSONArrayBuilder builder; builder.append(BSON("dc" << "NYC")); TagSet tags(BSONArray(builder.done())); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, SecNodeCompatibleTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = false; BSONArrayBuilder builder; builder.append(BSON("dc" << "NYC")); TagSet tags(BSONArray(builder.done())); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, PriNodeNotCompatibleTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = true; BSONArrayBuilder builder; builder.append(BSON("dc" << "SF")); TagSet tags(BSONArray(builder.done())); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, SecNodeNotCompatibleTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = false; BSONArrayBuilder builder; builder.append(BSON("dc" << "SF")); TagSet tags(BSONArray(builder.done())); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, PriNodeCompatiblMultiTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = true; BSONArrayBuilder builder; builder.append(BSON("dc" << "RP")); builder.append(BSON("dc" << "NYC" << "p" << "2")); TagSet tags(BSONArray(builder.done())); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, SecNodeCompatibleMultiTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = false; BSONArrayBuilder builder; builder.append(BSON("dc" << "RP")); builder.append(BSON("dc" << "NYC" << "p" << "2")); TagSet tags(BSONArray(builder.done())); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, PriNodeNotCompatibleMultiTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = true; BSONArrayBuilder builder; builder.append(BSON("dc" << "sf")); builder.append(BSON("dc" << "NYC" << "P" << "4")); TagSet tags(BSONArray(builder.done())); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags)); } TEST(ReplSetMonitorNode, SecNodeNotCompatibleMultiTag) { Node node(HostAndPort("dummy", 3)); node.tags = SampleTags; node.isUp = true; node.isMaster = false; BSONArrayBuilder builder; builder.append(BSON("dc" << "sf")); builder.append(BSON("dc" << "NYC" << "P" << "4")); TagSet tags(BSONArray(builder.done())); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags)); ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags)); } class NodeSetFixtures { public: static vector getThreeMemberWithTags(); }; vector NodeSetFixtures::getThreeMemberWithTags() { vector nodes; nodes.push_back(Node(HostAndPort("a"))); nodes.push_back(Node(HostAndPort("b"))); nodes.push_back(Node(HostAndPort("c"))); nodes[0].isUp = true; nodes[1].isUp = true; nodes[2].isUp = true; nodes[0].isMaster = false; nodes[1].isMaster = true; nodes[2].isMaster = false; nodes[0].tags = BSON("dc" << "nyc" << "p" << "1"); nodes[1].tags = BSON("dc" << "sf"); nodes[2].tags = BSON("dc" << "nyc" << "p" << "2"); return nodes; } class TagSetFixtures { public: static BSONArray getDefaultSet(); static BSONArray getP2Tag(); static BSONArray getSingleNoMatchTag(); static BSONArray getMultiNoMatchTag(); }; BSONArray TagSetFixtures::getDefaultSet() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSONObj()); return arrayBuilder.arr(); } BSONArray TagSetFixtures::getP2Tag() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "2")); return arrayBuilder.arr(); } BSONArray TagSetFixtures::getSingleNoMatchTag() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("k" << "x")); return arrayBuilder.arr(); } BSONArray TagSetFixtures::getMultiNoMatchTag() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("mongo" << "db")); arrayBuilder.append(BSON("by" << "10gen")); return arrayBuilder.arr(); } TEST(ReplSetMonitorReadPref, PrimaryOnly) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, PrimaryOnlyPriNotOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, PrimaryMissing) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[1].isMaster = false; bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, PriPrefWithPriOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 1, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, PriPrefWithPriNotOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 1, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT(host.host() == "a" || host.host() == "c"); } TEST(ReplSetMonitorReadPref, SecOnly) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, tags, 1, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(ReplSetMonitorReadPref, SecOnlyOnlyPriOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[0].markFailed(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, tags, 1, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecPref) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 1, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(ReplSetMonitorReadPref, SecPrefWithNoSecOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[0].markFailed(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 1, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, SecPrefWithNoNodeOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[0].markFailed(); nodes[1].markFailed(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 1, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, NearestAllLocal) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[0].latencyMicros = 1 * 1000; nodes[1].latencyMicros = 2 * 1000; nodes[2].latencyMicros = 3 * 1000; bool isPrimarySelected = 0; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); // Any host is ok ASSERT(!host.empty()); ASSERT_EQUALS(isPrimarySelected, host.host() == "b"); } TEST(ReplSetMonitorReadPref, NearestOneLocal) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getDefaultSet()); nodes[0].latencyMicros = 10 * 1000; nodes[1].latencyMicros = 20 * 1000; nodes[2].latencyMicros = 30 * 1000; bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT_EQUALS("a", host.host()); ASSERT(!isPrimarySelected); } TEST(ReplSetMonitorReadPref, PriOnlyWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getP2Tag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); // Note: PrimaryOnly ignores tag ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, PriPrefPriNotOkWithTags) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getP2Tag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST(ReplSetMonitorReadPref, PriPrefPriOkWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, PriPrefPriNotOkWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecOnlyWithTags) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getP2Tag()); bool isPrimarySelected; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST(ReplSetMonitorReadPref, SecOnlyWithTagsMatchOnlyPri) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("dc" << "sf")); TagSet tags(arrayBuilder.arr()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecPrefWithTags) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getP2Tag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST(ReplSetMonitorReadPref, SecPrefSecNotOkWithTags) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("dc" << "nyc")); TagSet tags(arrayBuilder.arr()); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(ReplSetMonitorReadPref, SecPrefPriOkWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, SecPrefPriNotOkWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecPrefPriOkWithSecNotMatchTag) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, NearestWithTags) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "1")); TagSet tags(arrayBuilder.arr()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(ReplSetMonitorReadPref, NearestWithTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getSingleNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, MultiPriOnlyTag) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(ReplSetMonitorReadPref, MultiPriOnlyPriNotOkTag) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, PriPrefPriOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "1")); arrayBuilder.append(BSON("p" << "2")); TagSet tags(arrayBuilder.arr()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } class MultiTags : public mongo::unittest::Test { public: vector getNodes() const { return NodeSetFixtures::getThreeMemberWithTags(); } const TagSet& getMatchesFirstTagSet() { if (matchFirstTags.get() != NULL) { return *matchFirstTags; } BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "1")); arrayBuilder.append(BSON("p" << "2")); matchFirstTags.reset(new TagSet(arrayBuilder.arr())); return *matchFirstTags; } const TagSet& getMatchesSecondTagSet() { if (matchSecondTags.get() != NULL) { return *matchSecondTags; } BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "3")); arrayBuilder.append(BSON("p" << "2")); arrayBuilder.append(BSON("p" << "1")); matchSecondTags.reset(new TagSet(arrayBuilder.arr())); return *matchSecondTags; } const TagSet& getMatchesLastTagSet() { if (matchLastTags.get() != NULL) { return *matchLastTags; } BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "12")); arrayBuilder.append(BSON("p" << "23")); arrayBuilder.append(BSON("p" << "19")); arrayBuilder.append(BSON("p" << "34")); arrayBuilder.append(BSON("p" << "1")); matchLastTags.reset(new TagSet(arrayBuilder.arr())); return *matchLastTags; } const TagSet& getMatchesPriTagSet() { if (matchPriTags.get() != NULL) { return *matchPriTags; } BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("dc" << "sf")); arrayBuilder.append(BSON("p" << "1")); matchPriTags.reset(new TagSet(arrayBuilder.arr())); return *matchPriTags; } private: scoped_ptr matchFirstTags; scoped_ptr matchSecondTags; scoped_ptr matchLastTags; scoped_ptr matchPriTags; }; TEST_F(MultiTags, MultiTagsMatchesFirst) { vector nodes = getNodes(); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, PriPrefPriNotOkMatchesFirstNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, PriPrefPriNotOkMatchesSecondTest) { vector nodes = getNodes(); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, PriPrefPriNotOkMatchesSecondNotOkTest) { vector nodes = getNodes(); nodes[1].markFailed(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, PriPrefPriNotOkMatchesLastTest) { vector nodes = getNodes(); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, PriPrefPriNotOkMatchesLastNotOkTest) { vector nodes = getNodes(); nodes[0].markFailed(); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(MultiTagsXXX, PriPrefPriOkNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(MultiTagsXXX, PriPrefPriNotOkNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecOnlyMatchesFirstTest) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_SecondaryOnly, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecOnlyMatchesFirstNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_SecondaryOnly, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, SecOnlyMatchesSecond) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, SecOnlyMatchesSecondNotOk) { vector nodes = getNodes(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecOnlyMatchesLast) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_SecondaryOnly, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecOnlyMatchesLastNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_SecondaryOnly, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecOnlyMultiTagsWithPriMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_SecondaryOnly, getMatchesPriTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecOnlyMultiTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecPrefMatchesFirst) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecPrefMatchesFirstNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, SecPrefMatchesSecond) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, SecPrefMatchesSecondNotOk) { vector nodes = getNodes(); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecPrefMatchesLast) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, SecPrefMatchesLastNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST_F(MultiTags, SecPrefMultiTagsWithPriMatch) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, getMatchesPriTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(MultiTagsXXX, SecPrefMultiTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(MultiTagsXXX, SecPrefMultiTagsNoMatchPriNotOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); nodes[1].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, NearestMatchesFirst) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_Nearest, getMatchesFirstTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST(MultiTagsXXX, NearestMatchesFirstNotOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "1")); arrayBuilder.append(BSON("dc" << "sf")); TagSet tags(arrayBuilder.arr()); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST_F(MultiTags, NearestMatchesSecond) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_Nearest, getMatchesSecondTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST_F(MultiTags, NearestMatchesSecondNotOk) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("z" << "2")); arrayBuilder.append(BSON("p" << "2")); arrayBuilder.append(BSON("dc" << "sf")); TagSet tags(arrayBuilder.arr()); nodes[2].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST_F(MultiTags, NearestMatchesLast) { vector nodes = getNodes(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_Nearest, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("a", host.host()); } TEST_F(MultiTags, NeatestMatchesLastNotOk) { vector nodes = getNodes(); nodes[0].markFailed(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_Nearest, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, NearestMultiTagsWithPriMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference_Nearest, getMatchesPriTagSet(), 3, &isPrimarySelected); ASSERT(isPrimarySelected); ASSERT_EQUALS("b", host.host()); } TEST(MultiTagsXXX, NearestMultiTagsNoMatch) { vector nodes = NodeSetFixtures::getThreeMemberWithTags(); TagSet tags(TagSetFixtures::getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference_Nearest, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(TagSet, DefaultConstructorMatchesAll) { TagSet tags; ASSERT_EQUALS(tags.getTagBSON(), BSON_ARRAY(BSONObj())); } // TODO: Port these existing tests here: replmonitor_bad_seed.js, repl_monitor_refresh.js /** * Warning: Tests running this fixture cannot be run in parallel with other tests * that uses ConnectionString::setConnectionHook */ class ReplicaSetMonitorTest : public mongo::unittest::Test { protected: void setUp() { _replSet.reset(new MockReplicaSet("test", 3)); _originalConnectionHook = ConnectionString::getConnectionHook(); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); ReplicaSetMonitor::initialize(); } void tearDown() { ConnectionString::setConnectionHook(_originalConnectionHook); ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: ConnectionString::ConnectionHook* _originalConnectionHook; boost::scoped_ptr _replSet; }; TEST_F(ReplicaSetMonitorTest, SeedWithPriOnlySecDown) { // Test to make sure that the monitor doesn't crash when // ConnectionString::connect returns NULL MockReplicaSet* replSet = getReplSet(); replSet->kill(replSet->getSecondaries()); // Create a monitor with primary as the only seed list and the two secondaries // down so a NULL connection object will be stored for these secondaries in // the _nodes vector. const string replSetName(replSet->getSetName()); set seedList; seedList.insert(HostAndPort(replSet->getPrimary())); ReplicaSetMonitor::createIfNeeded(replSetName, seedList); replSet->kill(replSet->getPrimary()); ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); // Trigger calls to Node::getConnWithRefresh monitor->startOrContinueRefresh().refreshAll(); } // Stress test case for a node that is previously a primary being removed from the set. // This test goes through configurations with different positions for the primary node // in the host list returned from the isMaster command. The test here is to make sure // that the ReplicaSetMonitor will not crash under these situations. TEST(ReplicaSetMonitorTestXXX, PrimaryRemovedFromSetStress) { const size_t NODE_COUNT = 5; MockReplicaSet replSet("test", NODE_COUNT); ConnectionString::ConnectionHook* originalConnHook = ConnectionString::getConnectionHook(); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); const string replSetName(replSet.getSetName()); set seedList; seedList.insert(HostAndPort(replSet.getPrimary())); ReplicaSetMonitor::initialize(); ReplicaSetMonitor::createIfNeeded(replSetName, seedList); const MockReplicaSet::ReplConfigMap origConfig = replSet.getReplConfig(); mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName); for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) { MockReplicaSet::ReplConfigMap newConfig = origConfig; replSet.setConfig(origConfig); // Make sure the monitor sees the change replMonitor->startOrContinueRefresh().refreshAll(); string hostToRemove; { BSONObjBuilder monitorStateBuilder; replMonitor->appendInfo(monitorStateBuilder); BSONObj monitorState = monitorStateBuilder.done(); BSONElement hostsElem = monitorState["hosts"]; BSONElement addrElem = hostsElem[mongo::str::stream() << idxToRemove]["addr"]; hostToRemove = addrElem.String(); } replSet.setPrimary(hostToRemove); // Make sure the monitor sees the new primary replMonitor->startOrContinueRefresh().refreshAll(); newConfig.erase(hostToRemove); replSet.setConfig(newConfig); replSet.setPrimary(newConfig.begin()->first); // Force refresh -> should not crash replMonitor->startOrContinueRefresh().refreshAll(); } ReplicaSetMonitor::shutdown(); ConnectionString::setConnectionHook(originalConnHook); } /** * Warning: Tests running this fixture cannot be run in parallel with other tests * that use ConnectionString::setConnectionHook. */ class TwoNodeWithTags : public mongo::unittest::Test { protected: void setUp() { _replSet.reset(new MockReplicaSet("test", 2)); _originalConnectionHook = ConnectionString::getConnectionHook(); ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); mongo::MockReplicaSet::ReplConfigMap config = _replSet->getReplConfig(); { const string host(_replSet->getPrimary()); map& tag = config[host].tags; tag.clear(); tag["dc"] = "ny"; tag["num"] = "1"; } { const string host(_replSet->getSecondaries().front()); map& tag = config[host].tags; tag.clear(); tag["dc"] = "ny"; tag["num"] = "2"; } _replSet->setConfig(config); ReplicaSetMonitor::initialize(); } void tearDown() { ConnectionString::setConnectionHook(_originalConnectionHook); ReplicaSetMonitor::shutdown(); _replSet.reset(); } MockReplicaSet* getReplSet() { return _replSet.get(); } private: ConnectionString::ConnectionHook* _originalConnectionHook; boost::scoped_ptr _replSet; }; // Tests the case where the connection to secondary went bad and the replica set // monitor needs to perform a refresh of it's local view then retry the node selection // again after the refresh. TEST_F(TwoNodeWithTags, SecDownRetryNoTag) { MockReplicaSet* replSet = getReplSet(); set seedList; seedList.insert(HostAndPort(replSet->getPrimary())); ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); const string secHost(replSet->getSecondaries().front()); replSet->kill(secHost); ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); // Make sure monitor sees the dead secondary monitor->startOrContinueRefresh().refreshAll(); replSet->restore(secHost); HostAndPort node = monitor->getHostOrRefresh( ReadPreferenceSetting(mongo::ReadPreference_SecondaryOnly, TagSet())); ASSERT_FALSE(monitor->isPrimary(node)); ASSERT_EQUALS(secHost, node.toString()); } // Tests the case where the connection to secondary went bad and the replica set // monitor needs to perform a refresh of it's local view then retry the node selection // with tags again after the refresh. TEST_F(TwoNodeWithTags, SecDownRetryWithTag) { MockReplicaSet* replSet = getReplSet(); set seedList; seedList.insert(HostAndPort(replSet->getPrimary())); ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); const string secHost(replSet->getSecondaries().front()); replSet->kill(secHost); ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); // Make sure monitor sees the dead secondary monitor->startOrContinueRefresh().refreshAll(); replSet->restore(secHost); TagSet tags(BSON_ARRAY(BSON("dc" << "ny"))); HostAndPort node = monitor->getHostOrRefresh(ReadPreferenceSetting(mongo::ReadPreference_SecondaryOnly, tags)); ASSERT_FALSE(monitor->isPrimary(node)); ASSERT_EQUALS(secHost, node.toString()); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/000077500000000000000000000000001273231111400206405ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/boundingbox.h000066400000000000000000000164451273231111400233410ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include "mongo/db/jsobj.h" #include "mongo/geo/constants.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { /** * Represents a bounding box. * * A bounding box describes the smallest box that can contain some * set of enclosed geometries. For example, the bounding box around * the LineString [(0, 0), (5, 0), (2, 6)] would be the rectangle with * coordinates [(0, 0), (5, 0), (5, 6), (0, 6)]. * * A bounding box is defined by the two points on its corners with the lowest and * highest values for all axes. The above bounding box is represented as: * * { "bbox" : [ 0, 0, 5, 6 ] } * * The first half of the array defines the coordinates of the low point and the * second half defines the coordinates of the high point. * * Bounding boxes are optional members of Geometries. The BSON for * the above LineString, if it included a defined bounding box, would be: * * { * "type" : "LineString", * "coordinates" : [ [ 0, 0 ], [ 5, 0 ], [ 2, 6 ] ], * "bbox" : [ 0, 0, 5, 6 ] * } * * Example Usage: * * BSONObj shapeBSON = cursor->next(); * MultiLineString mls(shapeBSON); * * // Find all geometry objects inside the bounding box of mls * BoundingBox bbox = mls.getBoundingBox(); * Query geowithinQuery = MONGO_QUERY("" << GEOWITHIN(bbox)); * conn.query(".", geowithinQuery); * * @see http://geojson.org/geojson-spec.html#bounding-boxes */ template class BoundingBox { public: /** * BoundingBox constructor * * @param min The minimum point of the box * @param max The maximum point of the box * * Example Usage: * * Coordinates2D min(0, 0); * Coordinates2D max(5, 6); * BoundingBox bbox(min, max); */ BoundingBox(const TCoordinates& min, const TCoordinates& max); /** * BoundingBox constructor * * @param bson BSON defining a Geometry that has a member "bbox". * * Note that to use this constructor, the BSON *must* already define * the bounding box. If the given BSON has no "bbox" member that defines * the bounding box of the shape, an assertion error is raised. * * If you have BSON defining a Geometry that has no bbox member * and you would like to find the shape's bounding box, call that shape's * constructor instead and use its .getBoundingBox() method. * * Example usage: * * BSONObj bson = BSON( * "type" << "LineString" * "coordinates" << BSON_ARRAY(BSON_ARRAY(0 << 0) << BSON_ARRAY(5 << 6)) * "bbox" << BSON_ARRAY(0 << 0 << 5 << 6)); * BoundingBox bbox(bson); */ explicit BoundingBox(const BSONObj& bson); /** * Get the minimum coordinates of this bounding box. * * @return TCoordinates that contain the minimum values * for each axis of this bounding box. */ TCoordinates getMin() const { return _min; } /** * Get the maximum coordinates of this bounding box. * * @return TCoordinates that contain the maximum values * for each axis of this bounding box. */ TCoordinates getMax() const { return _max; } /** * Obtain a BSON representation of this bounding box. * * Example BSON, representing minimum coordinates (0, 0) and maximum * coordinates (5, 6): * * { "bbox" : [ 0, 0, 5, 6 ] } * * @return A BSON representation of this bounding box. */ BSONObj toBSON() const; /** * Obtain a flat BSONArray representation of the coordinate values * defined by this bounding box. * * Example BSONArray, representing minimum coordinates (0, 0) and maximum * coordinates (5, 6): * * [ 0, 0, 5, 6 ] * * @return A flat BSONArray representation of the coordinate values. */ BSONArray toBSONArray() const; /** * Obtain a nested BSONArray representation of the coordinate values * defined by this bounding box. * * Example BSONArray, representing minimum coordinates (0, 0) and maximum * coordinates (5, 6): * * [ [ 0, 0 ], [ 5, 6 ] ] * * @return A nested BSONArray representation of the coordinate values. */ BSONArray toNestedBSONArray() const; private: TCoordinates _min; TCoordinates _max; }; template BoundingBox::BoundingBox(const TCoordinates& min, const TCoordinates& max) : _min(min), _max(max) {} template BoundingBox::BoundingBox(const BSONObj& bson) { BSONElement bbox = bson.getField(kBoundingBoxFieldName); // Ensure bson defines a bounding box. uassert(0, "bson argument to BoundingBox ctor must define the field \"bbox\"", !bbox.eoo()); std::vector bboxCoords = bbox.Array(); // The GeoJSON spec dictates that bboxCoords is an array of // length 2*n, where n is the number of dimensions represented // in the contained geometries. const size_t n = TCoordinates::dimensionality(); uassert(0, "bbox field must have exactly 2 * n elements, where n is the number of dimensions " "in the coordinate system", bboxCoords.size() == 2 * n); // Construct _min with the first n elements and _max with the second n elements. std::vector minCoords, maxCoords; for (size_t i = 0; i < n; ++i) { minCoords.push_back(bboxCoords[i].Double()); maxCoords.push_back(bboxCoords[n + i].Double()); } _min = TCoordinates(minCoords); _max = TCoordinates(maxCoords); } template BSONObj BoundingBox::toBSON() const { return BSON(kBoundingBoxFieldName << toBSONArray()); } template BSONArray BoundingBox::toBSONArray() const { BSONArrayBuilder bab; std::vector minCoords = _min.getValues(); std::vector maxCoords = _max.getValues(); for (size_t i = 0; i < minCoords.size(); ++i) bab.append(minCoords[i]); for (size_t i = 0; i < maxCoords.size(); ++i) bab.append(maxCoords[i]); return bab.arr(); } template BSONArray BoundingBox::toNestedBSONArray() const { BSONArrayBuilder minBab, maxBab; std::vector minCoords = _min.getValues(); std::vector maxCoords = _max.getValues(); for (size_t i = 0; i < minCoords.size(); ++i) minBab.append(minCoords[i]); for (size_t i = 0; i < maxCoords.size(); ++i) maxBab.append(maxCoords[i]); return BSON_ARRAY(minBab.arr() << maxBab.arr()); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/constants.h000066400000000000000000000032231273231111400230250ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once namespace mongo { namespace geo { /** * The special field names defined by the GeoJSON specification. */ const char kBoundingBoxFieldName[] = "bbox"; const char kCoordsFieldName[] = "coordinates"; const char kGeometriesFieldName[] = "geometries"; const char kTypeFieldName[] = "type"; /** * The different possible geometry type names in GeoJSON. */ const char kGeometryCollectionTypeStr[] = "GeometryCollection"; const char kLineStringTypeStr[] = "LineString"; const char kMultiLineStringTypeStr[] = "MultiLineString"; const char kMultiPointTypeStr[] = "MultiPoint"; const char kMultiPolygonTypeStr[] = "MultiPolygon"; const char kPointTypeStr[] = "Point"; const char kPolygonTypeStr[] = "Polygon"; /** * An enum to represent the type of geometry of a Geo object. */ enum GeoObjType { GeoObjType_GeometryCollection, GeoObjType_LineString, GeoObjType_MultiLineString, GeoObjType_MultiPoint, GeoObjType_MultiPolygon, GeoObjType_Point, GeoObjType_Polygon }; } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/coordinates.h000066400000000000000000000032611273231111400233250ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" namespace mongo { namespace geo { class MONGO_CLIENT_API Coordinates { public: virtual ~Coordinates() {} /** * Get the values of these coordinates as a vector of doubles. * * @return A vector of the values of these coordinates. */ virtual std::vector getValues() const = 0; /** * Obtain a BSON representation of these coordinates. * * Example structure: * { "coordinates" : [ value1, value2 ] } * * @return a BSON representation of this point. */ virtual BSONObj toBSON() const = 0; /** * Obtain the value of these coordinates in a particular dimension. * * @param dimension The dimension whose coordinate value to return. 0 for x or longitude, * 1 for y or latitude * * @return The value of these coordinates in the given dimension. */ virtual double operator[](size_t dimension) const = 0; }; } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/coordinates2d.cpp000066400000000000000000000037151273231111400241120ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #include "mongo/geo/coordinates2d.h" #include #include "mongo/db/jsobj.h" #include "mongo/geo/constants.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { Coordinates2D::Coordinates2D(const std::vector& coords) { uassert(0, "Number of elements in coords must match dimensionality of coordinate type", coords.size() == dimensionality()); _x = coords[0]; _y = coords[1]; } Coordinates2D::Coordinates2D(const std::pair& coords) { _x = coords.first; _y = coords.second; } std::vector Coordinates2D::getValues() const { double vals[] = {_x, _y}; return std::vector(vals, vals + sizeof(vals) / sizeof(vals[0])); } std::pair Coordinates2D::getValuesAsPair() const { return std::make_pair(_x, _y); } BSONObj Coordinates2D::toBSON() const { return BSON(kCoordsFieldName << BSON_ARRAY(_x << _y)); } double Coordinates2D::operator[](size_t dimension) const { switch (dimension) { case 0: return _x; case 1: return _y; default: uassert(0, "Attempt to access out-of-bounds element (only valid indices are 0 and 1 for" " Coordinates2D)", false); } } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/coordinates2d.h000066400000000000000000000065221273231111400235560ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/coordinates.h" namespace mongo { namespace geo { /** * Represents a 2D position (x, y). * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); * Query nearQuery = QUERY("" << NEAR(point)); * conn.query(".", nearQuery); */ class MONGO_CLIENT_API Coordinates2D : public Coordinates { public: Coordinates2D() : _x(0), _y(0) {} /** * Coordinates2D constructor * * @param coords The coordinate values. * * @pre coords.size() == Coordinates2D::dimensionality(). */ explicit Coordinates2D(const std::vector& coords); /** * Coordinates2D constructor * * @param coords The coordinate values. */ explicit Coordinates2D(const std::pair& coords); /** * Coordinates2D constructor * * @param x The x coordinate value. * @param y The y coordinate value. */ Coordinates2D(double x, double y) : _x(x), _y(y) {} /** * Get the x coordinate. * * @return double The x coordinate value. */ double getX() const { return _x; } /** * Get the y coordinate. * * @return double The y coordinate value. */ double getY() const { return _y; } /** * Get the x and y coordinates. * * @return std::vector A vector [x, y] of this object's * coordinate values. */ virtual std::vector getValues() const; /** * Get the x and y coordinates as a std::pair. * * @return std::pair A std::pair (x, y) of this * object's coordinate values. */ std::pair getValuesAsPair() const; /** * Get a BSON representation of the coordinates. * * @return BSONObj A BSONObj of the coordinates, structured as: * { "coordinates" : [ x, y ] } */ virtual BSONObj toBSON() const; /** * Get the value of this coordinate at the given dimension. * * @param dimension 0 -> x, 1 -> y, any other input * besides 0 or 1 is an error. * * @return The coordinate value at the given dimension. * * @pre 0 <= dimension < Coordinates2D::dimensionality() */ virtual double operator[](size_t dimension) const; /** * Get the dimensionality of this coordinate type. * * @return 2, the number of dimensions in Coordinates2D. */ static size_t MONGO_CLIENT_FUNC dimensionality() { return 2; } private: double _x; double _y; }; } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/coordinates2dgeographic.cpp000066400000000000000000000044241273231111400261410ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #include "mongo/geo/coordinates2dgeographic.h" #include #include "mongo/db/jsobj.h" #include "mongo/geo/constants.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { Coordinates2DGeographic::Coordinates2DGeographic(const std::vector& coords) { uassert(0, "Number of elements in coords must match dimensionality of coordinate type", coords.size() == dimensionality()); _longitude = coords[0]; _latitude = coords[1]; } Coordinates2DGeographic::Coordinates2DGeographic(const std::pair& coords) { _longitude = coords.first; _latitude = coords.second; } Coordinates2DGeographic::Coordinates2DGeographic(double longitude, double latitude) : _longitude(longitude), _latitude(latitude) {} std::vector Coordinates2DGeographic::getValues() const { double vals[] = {_longitude, _latitude}; return std::vector(vals, vals + sizeof(vals) / sizeof(vals[0])); } std::pair Coordinates2DGeographic::getValuesAsPair() const { return std::make_pair(_longitude, _latitude); } BSONObj Coordinates2DGeographic::toBSON() const { return BSON(kCoordsFieldName << BSON_ARRAY(_longitude << _latitude)); } double Coordinates2DGeographic::operator[](size_t dimension) const { switch (dimension) { case 0: return _longitude; case 1: return _latitude; default: uassert(0, "Attempt to access out-of-bounds element (only valid indices are 0 and 1 for" " Coordinates2DGeographic)", false); } } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/coordinates2dgeographic.h000066400000000000000000000071741273231111400256130ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/coordinates.h" namespace mongo { namespace geo { /** * Represents a 2D geographic position (longitude, latitude). * * Example Usage: * * Coordinates2DGeographic coords(1, 2); * Point point(coords); * Query nearQuery = QUERY("" << NEAR(point)); * conn.query(".", nearQuery); */ class MONGO_CLIENT_API Coordinates2DGeographic : public Coordinates { public: Coordinates2DGeographic() : _longitude(0), _latitude(0) {} /** * Coordinates2DGeographic constructor * * @param coords The coordinate values. * * @pre coords.size() == Coordinates2DGeographic::dimensionality(). */ explicit Coordinates2DGeographic(const std::vector& coords); /** * Coordinates2DGeographic constructor * * @param coords The coordinate values. */ explicit Coordinates2DGeographic(const std::pair& coords); /** * Coordinates2DGeographic constructor * * @param longitude The longitude value. * @param latitude The latitude value. */ Coordinates2DGeographic(double longitude, double latitude); /** * Get the longitude. * * @return double The longitude value. */ double getLongitude() const { return _longitude; } /** * Get the latitude. * * @return double The latitude value. */ double getLatitude() const { return _latitude; } /** * Get the longitude and latitude values as a vector. * * @return std::vector A vector [longitude, latitude] of this object's * coordinate values. */ virtual std::vector getValues() const; /** * Get the longitude and latitude values as a pair. * * @return std::pair A pair (longitude, latitude) of this * object's coordinate values. */ virtual std::pair getValuesAsPair() const; /** * Get a BSON representation of the coordinates. * * @return BSONObj A BSONObj of the coordinates, structured as: * { "coordinates" : [ longitude, latitude ] } */ virtual BSONObj toBSON() const; /** * Get the value of this coordinate at the given dimension. * * @param dimension 0 -> longitude, 1 -> latitude, any other input * besides 0 or 1 is an error. * * @return The coordinate value at the given dimension. * * @pre 0 <= dimension < Coordinates2DGeographic::dimensionality() */ virtual double operator[](size_t dimension) const; /** * Get the dimensionality of this coordinate type. * * @return 2, the number of dimensions in Coordinates2DGeographic. */ static size_t MONGO_CLIENT_FUNC dimensionality() { return 2; } private: double _longitude; double _latitude; }; } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/geo_test.cpp000066400000000000000000000130021273231111400231510ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include "mongo/unittest/unittest.h" #include "mongo/geo/interface.h" using std::vector; using namespace mongo::geo; using namespace mongo::unittest; using namespace mongo; namespace { bool eq(const Coordinates2D& a, const Coordinates2D& b) { return a.getValues() == b.getValues(); } bool eq(const Coordinates2DGeographic& a, const Coordinates2DGeographic& b) { return a.getValues() == b.getValues(); } BSONObj point(double x, double y) { return BSON("type" << "Point" << "coordinates" << BSON_ARRAY(x << y)); } const BSONObj kP1 = point(0, 0); const BSONObj kP2 = point(0, 5); const BSONObj kP3 = point(6, 7); const BSONObj kP4 = point(10, -5); const BSONObj kLowerBound = point(0, -5); const BSONObj kUpperBound = point(10, 7); vector > initPoints() { vector > points; points.push_back(Point(kP1)); points.push_back(Point(kP2)); points.push_back(Point(kP3)); points.push_back(Point(kP4)); return points; } const vector > kPoints = initPoints(); /* Coordinates2D Class */ TEST(Coordinates2D, GetValues) { const double x = 1; const double y = 2; Coordinates2D coords(x, y); vector values = coords.getValues(); ASSERT_EQUALS(values.size(), Coordinates2D::dimensionality()); ASSERT_EQUALS(values[0], x); ASSERT_EQUALS(values[1], y); } /* Coordinates2DGeographic Class */ TEST(Coordinates2DGeographic, GetValues) { const double lon = 1; const double lat = 2; Coordinates2DGeographic coords(lon, lat); vector values = coords.getValues(); ASSERT_EQUALS(values.size(), Coordinates2D::dimensionality()); ASSERT_EQUALS(values[0], lon); ASSERT_EQUALS(values[1], lat); } /* Point Class */ TEST(Point, BSONConstructor) { Point p1(kP1); Point p2(kP2); ASSERT_EQUALS(kP2, p2.toBSON()); ASSERT_EQUALS(kP1, p1.toBSON()); } class PointTest : public ::testing::Test { protected: PointTest() : p1x(0), p1y(0), p2x(0), p2y(5), p3x(6), p3y(7), p4x(10), p4y(-5) , p1(kP1), p2(kP2), p3(kP3), p4(kP4) {} const double p1x; const double p1y; const double p2x; const double p2y; const double p3x; const double p3y; const double p4x; const double p4y; Point p1; Point p2; Point p3; Point p4; }; TEST_F(PointTest, GetType) { ASSERT_EQUALS(p1.getType(), GeoObjType_Point); } TEST_F(PointTest, GetCoordinates) { ASSERT_TRUE(eq(p1.getCoordinates(), Coordinates2D(p1x, p1y))); } TEST_F(PointTest, BoundingBox) { BoundingBox bb = p1.getBoundingBox(); ASSERT_TRUE(eq(bb.getMin(), bb.getMax())); ASSERT_TRUE(eq(bb.getMin(), p1.getCoordinates())); } TEST_F(PointTest, OperatorBrackets) { ASSERT_EQUALS(p4[0], p4x); ASSERT_EQUALS(p4[1], p4y); ASSERT_ANY_THROW(p4[-1]); // out of bounds ASSERT_ANY_THROW(p4[2]); // out of bounds } TEST_F(PointTest, Assignment) { Point p = p1; ASSERT_TRUE(eq(p.getCoordinates(), p1.getCoordinates())); ASSERT_EQUALS(p.toBSON(), p1.toBSON()); } /* LineString Class */ class LineStringTest : public ::testing::Test { protected: LineStringTest() : ls(kPoints), lowerBound(Point(kLowerBound).getCoordinates()), upperBound(Point(kUpperBound).getCoordinates()) {} LineString ls; Coordinates2D lowerBound; Coordinates2D upperBound; }; TEST_F(LineStringTest, GetType) { ASSERT_EQUALS(ls.getType(), GeoObjType_LineString); } TEST_F(LineStringTest, BoundingBox) { BoundingBox bb = ls.getBoundingBox(); ASSERT_TRUE(eq(bb.getMin(), lowerBound)); ASSERT_TRUE(eq(bb.getMax(), upperBound)); } /* Polygon Class */ class PolygonTest : public ::testing::Test { protected: PolygonTest() : poly(addLSToVector(LineString(kPoints))), lowerBound(Point(kLowerBound).getCoordinates()), upperBound(Point(kUpperBound).getCoordinates()) {} vector > addLSToVector(const LineString& ls) { vector > vec; vec.push_back(ls); return vec; } mongo::geo::Polygon poly; Coordinates2D lowerBound; Coordinates2D upperBound; }; TEST_F(PolygonTest, GetType) { ASSERT_EQUALS(poly.getType(), GeoObjType_Polygon); } TEST_F(PolygonTest, BoundingBox) { BoundingBox bb = poly.getBoundingBox(); ASSERT_TRUE(eq(bb.getMin(), lowerBound)); ASSERT_TRUE(eq(bb.getMax(), upperBound)); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/geometry.h000066400000000000000000000200741273231111400226470ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geoobj.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { // forward declaration needed for Geometry's static helpers template class Point; template class Geometry : public GeoObj { protected: static BSONElement getCoordsField(const BSONObj& bson); static std::vector parseCoords(const BSONElement& coordArr); static std::vector parseCoords(const BSONObj& bson); static Point parsePoint(const BSONElement& coordArr); static std::vector > parsePointArray( const std::vector& pointArr); static std::vector > parseAllPoints(const BSONObj& bson); /** * Compute the bounding box around the given points. Caller has ownership of * the returned pointer. * * @param points The points that the computed bounding box will surround. * * @return A pointer to a bounding box around the given points. */ static BoundingBox* computeBoundingBox( const std::vector >& points); /** * Compute the smallest bounding box that contains the given bounding boxes. * This can also be thought of as the one large bounding box around the union * of points contained in the several smaller bounding boxes passed to this function. * Caller had ownership of the returned pointer. * * @param bboxes the bounding boxes that the computed bounding box will surround. * * @return A pointer to a bounding box around the given bounding boxes. */ static BoundingBox* computeBoundingBox( const std::vector >& bboxes); /** * Parses the bounding box defined by the given geometry shape, represented * in BSON. Caller had ownership of the returned pointer. * * @param bson The BSON for the geometry shape. * * @return If the shape defines its own bounding box with the "bbox" field, * returns a pointer to an instantiated bounding box around the shape. * Otherwise returns NULL. */ static BoundingBox* parseBoundingBox(const BSONObj& bson); private: static void findMinAndMaxCoordinatesOfDimension(const std::vector >& points, size_t dimension, double* min, double* max); }; template BSONElement Geometry::getCoordsField(const BSONObj& bson) { BSONElement coordsField = bson.getField(kCoordsFieldName); uassert(0, "bson must contain a field \"coordinates\" of type Array", !coordsField.eoo() && coordsField.type() == Array); return coordsField; } template std::vector Geometry::parseCoords(const BSONElement& coordArr) { std::vector coordElems = coordArr.Array(); std::vector coords; for (size_t i = 0; i < coordElems.size(); ++i) coords.push_back(coordElems[i].Double()); return coords; } template std::vector Geometry::parseCoords(const BSONObj& bson) { return parseCoords(getCoordsField(bson)); } template Point Geometry::parsePoint(const BSONElement& coordArr) { TCoordinates pointCoords(parseCoords(coordArr)); return Point(pointCoords); } template std::vector > Geometry::parsePointArray( const std::vector& pointArr) { std::vector > points; for (size_t i = 0; i < pointArr.size(); ++i) { points.push_back(parsePoint(pointArr[i])); } return points; } template std::vector > Geometry::parseAllPoints(const BSONObj& bson) { return parsePointArray(getCoordsField(bson).Array()); } template BoundingBox* Geometry::computeBoundingBox( const std::vector >& points) { // For a TCoordinates type with dimensions d1, d2, ..., dn, // the bounding box of these points will have min coordinates // whose d1 value is the minimum of all d1-axis values in points, // whose d2 value is the minimum of all d2-axis values in points, // and so on up through dn. Similarly for the max coordinates. // // So to compute the bounding box, we iterate through each dimension // and find the min / max values in points for that dimension. std::vector minCoordComponents, maxCoordComponents; for (size_t i = 0; i < TCoordinates::dimensionality(); ++i) { double min, max; findMinAndMaxCoordinatesOfDimension(points, i, &min, &max); minCoordComponents.push_back(min); maxCoordComponents.push_back(max); } TCoordinates minCoords(minCoordComponents); TCoordinates maxCoords(maxCoordComponents); return new BoundingBox(minCoords, maxCoords); } template void Geometry::findMinAndMaxCoordinatesOfDimension( const std::vector >& points, size_t dimension, double* min, double* max) { // Initialize min and max to the positive and negative double values // farthest from 0, respectively. Note that we initialize max to // -::max(). Initializing to ::min() is incorrect because it returns // the smallest positive normalized double, which is still greater than // every negative double (and coordinates can have negative values). *min = std::numeric_limits::max(); *max = -std::numeric_limits::max(); // Update min and max with the smallest and largest values for the given dimension. for (size_t i = 0; i < points.size(); ++i) { if (points[i][dimension] < *min) *min = points[i][dimension]; if (points[i][dimension] > *max) *max = points[i][dimension]; } } template BoundingBox* Geometry::computeBoundingBox( const std::vector >& bboxes) { if (bboxes.empty()) return NULL; std::vector minCoords = bboxes[0].getMin().getValues(); std::vector maxCoords = bboxes[0].getMax().getValues(); for (size_t i = 1; i < bboxes.size(); ++i) { std::vector curMin = bboxes[i].getMin().getValues(); std::vector curMax = bboxes[i].getMax().getValues(); for (size_t j = 0; j < curMin.size(); ++j) { minCoords[j] = std::min(minCoords[j], curMin[j]); maxCoords[j] = std::max(maxCoords[j], curMax[j]); } } TCoordinates globalMin(minCoords), globalMax(maxCoords); return new BoundingBox(globalMin, globalMax); } template BoundingBox* Geometry::parseBoundingBox(const BSONObj& bson) { if (bson.hasField(kBoundingBoxFieldName)) return new BoundingBox(bson); return NULL; } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/geometrycollection.h000066400000000000000000000133071273231111400247240ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/parser.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { // forward declaration needed to parse arbitrary geometries template class Parser; template class GeometryCollection : public Geometry { public: /** * GeometryCollection constructor * * @param bson A BSON representation of the geometry collection. */ explicit GeometryCollection(const BSONObj& bson); /** * Frees the heap memory for each geometry stored in this collection. */ ~GeometryCollection(); /** * Obtain a BSON representation of this geometry collection. * * Example structure: * * { * "type" : "GeometryCollection", * "geometries" : [ * { * "type": "Point", * "coordinates": [ 100.0, 0.0 ] * }, * { * "type": "LineString", * "coordinates": [ [ 101.0, 0.0 ], [ 102.0, 1.0 ] ] * } * ] * } * * @return a BSON representation of this geometry collection. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding the set of geometries in this * geometry collection. * * @return A bounding box containing every geometry in this collection. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_GeometryCollection */ virtual GeoObjType getType() const { return GeoObjType_GeometryCollection; } /** * Get a vector of pointers to the geometries contained in this geometry collection. * Each GeoObj has been instantiated as the appropriate subclass of GeoObj. To determine * the specific type of each pointed-to object, call ->getType() on the pointer. * * This GeometryCollection object has ownership of the const GeoObj*'s returned. * * @return a vector of const pointers to the geometries in this collection. */ const std::vector*>& getGeometries() const; private: /** * Parse the geometries defined in a geometry collection that is represented in BSON. * Caller has ownership of the returned pointers. * * @return a vector of const pointers to each geometry in defined in the collection. */ static std::vector*> parseGeometries(const BSONObj& bson); BSONObj _bson; std::vector*> _geometries; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this GeometryCollection. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this GeometryCollection. */ BoundingBox* computeBoundingBox() const; }; template GeometryCollection::GeometryCollection(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kGeometryCollectionTypeStr)), _geometries(parseGeometries(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template GeometryCollection::~GeometryCollection() { for (size_t i = 0; i < _geometries.size(); ++i) delete _geometries[i]; } template BoundingBox GeometryCollection::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template const std::vector*>& GeometryCollection::getGeometries() const { return _geometries; } template std::vector*> GeometryCollection::parseGeometries( const BSONObj& bson) { BSONElement geometriesField = bson.getField(kGeometriesFieldName); uassert(0, "bson must contain a field \"geometries\" of type Array", !geometriesField.eoo() && geometriesField.type() == Array); std::vector geometriesArr = geometriesField.Array(); std::vector*> geometries; for (size_t i = 0; i < geometriesArr.size(); ++i) { geometries.push_back(Parser::parse(geometriesArr[i].Obj())); } return geometries; } template BoundingBox* GeometryCollection::computeBoundingBox() const { std::vector > bboxes; for (size_t i = 0; i < _geometries.size(); ++i) bboxes.push_back(_geometries[i]->getBoundingBox()); return Geometry::computeBoundingBox(bboxes); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/geoobj.h000066400000000000000000000040321273231111400222550ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { template class GeoObj { public: virtual ~GeoObj() {} /** * Obtain a BSON representation of this GeoObj. * * @return A BSON representation of this GeoObj. */ virtual BSONObj toBSON() const = 0; /** * Obtain the bounding box of this GeoObj. * * @return The bounding box of this GeoObj. */ virtual BoundingBox getBoundingBox() const = 0; /** * Get the geometry type of this object. * * @return The appropriate GeoObjType enum value for this object. */ virtual GeoObjType getType() const = 0; protected: static BSONObj validateType(const BSONObj& bson, const StringData& typeStr); }; template BSONObj GeoObj::validateType(const BSONObj& bson, const StringData& typeStr) { BSONElement typeField = bson.getField(kTypeFieldName); uassert(0, "bson must be a valid " + typeStr.toString() + " type", !typeField.eoo() && ((typeField.type() == String) || (typeField.String() == typeStr))); return bson; } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/interface.h000066400000000000000000000027321273231111400227550ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/coordinates.h" #include "mongo/geo/coordinates2d.h" #include "mongo/geo/coordinates2dgeographic.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geometrycollection.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/linestring.h" #include "mongo/geo/multilinestring.h" #include "mongo/geo/multipoint.h" #include "mongo/geo/multipolygon.h" #include "mongo/geo/namespaces.h" #include "mongo/geo/parser.h" #include "mongo/geo/point.h" #include "mongo/geo/polygon.h" #include "mongo/geo/queryutils.h" // NOTE: parser-impl.h MUST be included after parser.h // and all geometry type files. This is a workaround to a circular dependency // issue between parser.h and geometrycollection.h. See // file comments in parser-impl.h for details. #include "mongo/geo/parser-impl.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/linestring.h000066400000000000000000000115501273231111400231710ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/point.h" namespace mongo { namespace geo { template class LineString : public Geometry { public: /** * LineString constructor * * @param bson A BSON representation of the line string. */ explicit LineString(const BSONObj& bson); /** * LineString constructor * * @param points The points that make up the line string. */ explicit LineString(const std::vector >& points); LineString(const LineString& other); LineString& operator=(LineString other); /** * Obtain a BSON representation of the line string. * * @return a BSON representation of the line string. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding this line string. * * @return A bounding box surrounding this line string. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_LineString */ virtual GeoObjType getType() const { return GeoObjType_LineString; } /** * Obtain the points that make up this LineString. * * @return a vector of points making up this LineString. */ std::vector > getPoints() const { return _points; } private: static BSONObj createBSON(const std::vector >& points); BSONObj _bson; std::vector > _points; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this LineString. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this LineString. */ BoundingBox* computeBoundingBox() const; }; template LineString::LineString(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kLineStringTypeStr)), _points(Geometry::parseAllPoints(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template LineString::LineString(const std::vector >& points) : _bson(createBSON(points)), _points(points) {} template LineString::LineString(const LineString& other) : _bson(other._bson), _points(other._points) { // TODO: consider refactoring this to not make deep copies, // and instead use a boost::shared_ptr to share the same bounding // box across all copies of a Point. This would also let the // compiler generate copy and assignment constructors, so we can drop // them from the implementation. if (other._boundingBox) _boundingBox.reset(new BoundingBox(*other._boundingBox)); } template LineString& LineString::operator=(LineString other) { using std::swap; swap(_bson, other._bson); swap(_points, other._points); swap(_boundingBox, other._boundingBox); return *this; } template BoundingBox LineString::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template BSONObj LineString::createBSON(const std::vector >& points) { BSONArrayBuilder bab; for (size_t i = 0; i < points.size(); ++i) bab.append(points[i].toBSON()[kCoordsFieldName]); BSONObjBuilder bob; return bob.append(kTypeFieldName, kLineStringTypeStr).append(kCoordsFieldName, bab.arr()).obj(); } template BoundingBox* LineString::computeBoundingBox() const { return Geometry::computeBoundingBox(_points); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/multilinestring.h000066400000000000000000000130531273231111400242440ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" namespace mongo { namespace geo { template class MultiLineString : public Geometry { public: /** * MultiLineString constructor * * @param bson A BSON representation of this MultiLineString. */ explicit MultiLineString(const BSONObj& bson); /** * MultiLineString constructor * * @param lineStrings the LineStrings that collectively make up this MultiLineString. */ explicit MultiLineString(const std::vector >& lineStrings); /** * Obtain a BSON representation of the MultiLineString. * * @return a BSON representation of the MultiLineString. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding this MultiLineString. * * @return A bounding box surrounding this MultiLineString. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_MultiLineString */ virtual GeoObjType getType() const { return GeoObjType_MultiLineString; } /** * Obtain the points that make up this MultiLineString. * * @return a vector of points making up this MultiLineString. */ std::vector > getPoints() const; /** * Obtain the line strings that make up this MultiLineString. * * @return a vector of LineStrings making up this MultiLineString. */ std::vector > getLineStrings() const; private: static BSONObj createBSON(const std::vector >& lineStrings); static std::vector > parseLineStrings(const BSONObj& bson); BSONObj _bson; std::vector > _lineStrings; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this MultiLineString. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this MultiLineString. */ BoundingBox* computeBoundingBox() const; }; template MultiLineString::MultiLineString(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kMultiLineStringTypeStr)), _lineStrings(parseLineStrings(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template MultiLineString::MultiLineString( const std::vector >& lineStrings) : _bson(createBSON(lineStrings)), _lineStrings(lineStrings) {} template BoundingBox MultiLineString::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template std::vector > MultiLineString::getPoints() const { std::vector > points, curLineStringPoints; for (size_t i = 0; i < _lineStrings.size(); ++i) { curLineStringPoints = _lineStrings[i].getPoints(); points.insert(points.end(), curLineStringPoints.begin(), curLineStringPoints.end()); } return points; } template std::vector > MultiLineString::getLineStrings() const { return _lineStrings; } template BSONObj MultiLineString::createBSON( const std::vector >& lineStrings) { BSONArrayBuilder bab; for (size_t i = 0; i < lineStrings.size(); ++i) bab.append(lineStrings[i].toBSON()[kCoordsFieldName]); BSONObjBuilder bob; return bob.append(kTypeFieldName, kMultiLineStringTypeStr) .append(kCoordsFieldName, bab.arr()) .obj(); } template std::vector > MultiLineString::parseLineStrings( const BSONObj& bson) { std::vector lineStringArr = Geometry::getCoordsField(bson).Array(); std::vector > lineStrings; for (size_t i = 0; i < lineStringArr.size(); ++i) { LineString line( Geometry::parsePointArray(lineStringArr[i].Array())); lineStrings.push_back(line); } return lineStrings; } template BoundingBox* MultiLineString::computeBoundingBox() const { return Geometry::computeBoundingBox(getPoints()); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/multipoint.h000066400000000000000000000061151273231111400232200ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" namespace mongo { namespace geo { template class MultiPoint : public Geometry { public: /** * MultiPoint constructor * * @param bson A BSON representation of this MultiPoint. */ explicit MultiPoint(const BSONObj& bson); /** * Obtain a BSON representation of the MultiPoint. * * @return a BSON representation of the MultiPoint. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding this MultiPoint. * * @return A bounding box surrounding this MultiPoint. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_MultiPoint */ virtual GeoObjType getType() const { return GeoObjType_MultiPoint; } /** * Obtain the points that make up this MultiPoint. * * @return a vector of points making up this MultiPoint. */ std::vector > getPoints() const { return _points; } private: BSONObj _bson; std::vector > _points; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this MultiPoint. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this MultiPoint. */ BoundingBox* computeBoundingBox() const; }; template MultiPoint::MultiPoint(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kMultiPointTypeStr)), _points(Geometry::parseAllPoints(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template BoundingBox MultiPoint::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template BoundingBox* MultiPoint::computeBoundingBox() const { return Geometry::computeBoundingBox(_points); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/multipolygon.h000066400000000000000000000115211273231111400235530ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" #include "mongo/geo/polygon.h" namespace mongo { namespace geo { template class MultiPolygon : public Geometry { public: /** * MultiPolygon constructor * * @param bson A BSON representation of this MultiPolygon. */ explicit MultiPolygon(const BSONObj& bson); /** * Obtain a BSON representation of the MultiPolygon. * * @return a BSON representation of the MultiPolygon. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding this MultiPolygon. * * @return A bounding box surrounding this MultiPolygon. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_MultiPolygon */ virtual GeoObjType getType() const { return GeoObjType_MultiPolygon; } /** * Obtain the points that make up this MultiPolygon. * * @return a vector of points making up this MultiPolygon. */ std::vector > getPoints() const; /** * Obtain the Polygons that make up this MultiPolygon. * * @return a vector of Polygons making up this MultiPolygon. */ std::vector > getPolygons() const { return _polygons; } private: static Polygon parsePolygon(const BSONElement& polygon); static std::vector > parseAllPolygons(const BSONObj& bson); BSONObj _bson; std::vector > _polygons; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this MultiPolygon. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this MultiPolygon. */ BoundingBox* computeBoundingBox() const; }; template MultiPolygon::MultiPolygon(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kMultiPolygonTypeStr)), _polygons(parseAllPolygons(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template BoundingBox MultiPolygon::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template std::vector > MultiPolygon::getPoints() const { std::vector > points, curPolygonPoints; for (size_t i = 0; i < _polygons.size(); ++i) { curPolygonPoints = _polygons[i].getPoints(); points.insert(points.end(), curPolygonPoints.begin(), curPolygonPoints.end()); } return points; } template Polygon MultiPolygon::parsePolygon(const BSONElement& polygon) { std::vector linearRingElems = polygon.Array(); std::vector > linearRings; for (size_t i = 0; i < linearRingElems.size(); ++i) { linearRings.push_back(LineString( Geometry::parsePointArray(linearRingElems[i].Array()))); } return Polygon(linearRings); } template std::vector > MultiPolygon::parseAllPolygons( const BSONObj& bson) { std::vector polygonArr = Geometry::getCoordsField(bson).Array(); std::vector > polygons; for (size_t i = 0; i < polygonArr.size(); ++i) { polygons.push_back(parsePolygon(polygonArr[i])); } return polygons; } template BoundingBox* MultiPolygon::computeBoundingBox() const { return Geometry::computeBoundingBox(getPoints()); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/namespaces.h000066400000000000000000000046441273231111400231400ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/geo/coordinates2d.h" #include "mongo/geo/coordinates2dgeographic.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/coordinates.h" #include "mongo/geo/geometry.h" #include "mongo/geo/geometrycollection.h" #include "mongo/geo/linestring.h" #include "mongo/geo/multilinestring.h" #include "mongo/geo/multipoint.h" #include "mongo/geo/multipolygon.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" #include "mongo/geo/polygon.h" #include "mongo/geo/parser.h" namespace mongo { namespace geo { namespace coords2d { typedef BoundingBox BoundingBox; typedef Geometry Geometry; typedef GeometryCollection GeometryCollection; typedef LineString LineString; typedef MultiLineString MultiLineString; typedef MultiPoint MultiPoint; typedef MultiPolygon MultiPolygon; typedef GeoObj GeoObj; typedef Point Point; typedef Polygon Polygon; typedef Parser Parser; } // namespace coords2d namespace coords2dgeographic { typedef BoundingBox BoundingBox; typedef Geometry Geometry; typedef GeometryCollection GeometryCollection; typedef LineString LineString; typedef MultiLineString MultiLineString; typedef MultiPoint MultiPoint; typedef MultiPolygon MultiPolygon; typedef GeoObj GeoObj; typedef Point Point; typedef Polygon Polygon; typedef Parser Parser; } // namespace coords2dgeographic } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/parser-impl.h000066400000000000000000000057001273231111400232460ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include "mongo/base/string_data.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/linestring.h" #include "mongo/geo/multilinestring.h" #include "mongo/geo/multipoint.h" #include "mongo/geo/multipolygon.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" #include "mongo/geo/polygon.h" #include "mongo/geo/parser.h" #include "mongo/util/assert_util.h" namespace mongo { namespace geo { template GeoObj* Parser::parse(const BSONObj& bson) { BSONElement typeField = bson.getField(kTypeFieldName); uassert(0, "bson argument must have field \"type\" that has value of type string.", !typeField.eoo() && typeField.type() == String); switch (stringToType(typeField.String())) { case GeoObjType_Point: return new Point(bson); case GeoObjType_MultiPoint: return new MultiPoint(bson); case GeoObjType_LineString: return new LineString(bson); case GeoObjType_MultiLineString: return new MultiLineString(bson); case GeoObjType_Polygon: return new Polygon(bson); case GeoObjType_MultiPolygon: return new MultiPolygon(bson); case GeoObjType_GeometryCollection: return new GeometryCollection(bson); default: uassert(0, "bson must contain a type supported by MongoDB.", false); } } template GeoObjType Parser::stringToType(const StringData& typeStr) { if (typeStr == kPointTypeStr) return GeoObjType_Point; if (typeStr == kLineStringTypeStr) return GeoObjType_LineString; if (typeStr == kPolygonTypeStr) return GeoObjType_Polygon; if (typeStr == kMultiPointTypeStr) return GeoObjType_MultiPoint; if (typeStr == kMultiLineStringTypeStr) return GeoObjType_MultiLineString; if (typeStr == kMultiPolygonTypeStr) return GeoObjType_MultiPolygon; if (typeStr == kGeometryCollectionTypeStr) return GeoObjType_GeometryCollection; uassert(0, "typeStr must contain a GeoJSON type supported by MongoDB", false); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/parser.h000066400000000000000000000034031273231111400223050ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/constants.h" #include "mongo/geo/geoobj.h" namespace mongo { namespace geo { template class Parser { public: /** * Parse the given BSON into a geometry type. Caller has ownership * of the returned pointer. An assertion is raised if the BSON is not a * valid GeoJSON object. * * @param bson The BSON defining the geometry type. Must be a valid GeoJSON * object and define a "type" field that describes its specific geometry. * * @return A pointer to the instantiated geometry object. This object will * be instantiated as the appropriate subclass of GeoObj. E.g., if the bson * parameter defines a LineString, the returned GeoObj* actually points to a * LineString. So the returned GeoObj* can be statically cast to a LineString* * in such case. */ static GeoObj* parse(const BSONObj& bson); private: static GeoObjType stringToType(const StringData& typeStr); }; } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/point.h000066400000000000000000000152631273231111400221510ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file Represents a Point geometry. * * Example BSON structure: * * { * type : "Point", * coordinates : [ 1, 2 ] * } * */ #pragma once #include #include #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" namespace mongo { namespace geo { /** * Represents a Point. * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); * Query nearPointQuery = MONGO_QUERY("loc" << NEAR(point)); * conn.query("foo.bar", nearPointQuery); */ template class Point : public Geometry { public: /** * Point constructor * * @param bson A BSON representation of the point. * * Example Usage: * * Point point(BSON( * "type" << "Point" << * "coordinates" << BSON_ARRAY(1 << 2))); */ explicit Point(const BSONObj& bson); /** * Point constructor * * @param coords The coordinates of the point. * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); */ explicit Point(const TCoordinates& coords); Point(const Point& other); Point& operator=(Point other); /** * Obtain a BSON representation of this point. * * @return a BSON representation of this point. * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); * BSONObj bson = point.toBSON(); * * std::cout << bson.jsonString() << std::endl; * { "type" : "Point", "coordinates" : [ 1, 2 ] } */ virtual BSONObj toBSON() const { return _bson; } /** * Get the bounding box of this point. The bounding box of any * single Point is just the point itself. * * @return A bounding box with minimum and maximum coordinates * equal to the coordinates of this point. * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); * BoundingBox bbox = point.getBoundingBox(); */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. Useful * if you have a generic GeoObj* and you * want to determine what specific type it is. * * @see Parser * * @return GeoObjType_Point * * Example Usage: * * BSONObj unknownGeoObject = cursor->next(); * GeoObj* obj = Parser::parse(unknownGeoObject); * if (obj->getType() == GeoObjType_Point) { * Point* pointPtr = static_cast< Point* >obj; * // do things with pointPtr... * } else if ... */ virtual GeoObjType getType() const { return GeoObjType_Point; } /** * Get the coordinates of this point. * * @return The coordinates of this point. * * Example Usage: * * Point point(BSON( * "type" << "Point" << * "coordinates" << BSON_ARRAY(1 << 2))); * Coordinates2D coords = point.getCoordinates(); * std::cout << coords.toBSON().jsonString() << std::endl; * { "coordinates": [ 1, 2 ] } */ TCoordinates getCoordinates() const { return _coords; } /** * Get the position of this point in the given dimension. * * @param dimension The coordinate dimension sought. * * @return The value of this point's position in the given dimension. * * Example Usage: * * Coordinates2D coords(1, 2); * Point point(coords); * for (size_t i = 0; i < coords::dimensionality(); ++i) * std::cout << point[i] << " "; * "1 2 " */ double operator[](size_t dimension) const { return _coords[dimension]; } private: static BSONObj createBSON(const TCoordinates& coords); BSONObj _bson; TCoordinates _coords; mutable boost::scoped_ptr > _boundingBox; BoundingBox* computeBoundingBox() const; }; template Point::Point(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kPointTypeStr)), _coords(Geometry::parseCoords(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template Point::Point(const TCoordinates& coords) : _bson(createBSON(coords)), _coords(coords) {} template Point::Point(const Point& other) : _bson(other._bson), _coords(other._coords) { // TODO: consider refactoring this to not make deep copies, // and instead use a boost::shared_ptr to share the same bounding // box across all copies of a Point. This would also let the // compiler generate copy and assignment constructors, so we can drop // them from the implementation. if (other._boundingBox) _boundingBox.reset(new BoundingBox(*other._boundingBox)); } template Point& Point::operator=(Point other) { using std::swap; swap(_bson, other._bson); swap(_coords, other._coords); swap(_boundingBox, other._boundingBox); return *this; } template BoundingBox Point::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template BSONObj Point::createBSON(const TCoordinates& coords) { BSONObjBuilder bob; return bob.append(kTypeFieldName, kPointTypeStr).appendElements(coords.toBSON()).obj(); } template BoundingBox* Point::computeBoundingBox() const { return new BoundingBox(_coords, _coords); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/polygon.h000066400000000000000000000145741273231111400225130ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file */ #pragma once #include #include #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geometry.h" #include "mongo/geo/linestring.h" #include "mongo/geo/geoobj.h" #include "mongo/geo/point.h" namespace mongo { namespace geo { template class Polygon : public Geometry { public: /** * Polygon constructor * * @param bson A BSON representation of the polygon. */ explicit Polygon(const BSONObj& bson); /** * Polygon constructor * * @param linearRings The linear rings that define this polygon. * The first element represents the exterior linear ring. Any subsequent * elements represent interior rings (or holes). */ explicit Polygon(const std::vector >& linearRings); Polygon(const Polygon& other); Polygon& operator=(Polygon other); /** * Obtain a BSON representation of the polygon. * * @return a BSON representation of the polygon. */ virtual BSONObj toBSON() const { return _bson; } /** * Obtain the bounding box surrounding this Polygon. * * @return A bounding box surrounding this Polygon. */ virtual BoundingBox getBoundingBox() const; /** * Get the geometry type of this object. * * @return GeoObjType_Polygon */ virtual GeoObjType getType() const { return GeoObjType_Polygon; } /** * Obtain the points that make up this Polygon. * * @return a vector of points making up this Polygon. */ std::vector > getPoints() const; /** * Obtain the linear rings that make up this Polygon. * * @return a vector of LineStrings that define the linear rings * making up this Polygon. */ std::vector > getLinearRings() const; private: static BSONObj createBSON(const std::vector >& linearRings); static std::vector > parseLinearRings(const BSONObj& bson); BSONObj _bson; std::vector > _linearRings; mutable boost::scoped_ptr > _boundingBox; /** * Compute the bounding box arround this Polygon. Caller has ownership of the * returned pointer. * * @return a pointer to the bounding box of this Polygon. */ BoundingBox* computeBoundingBox() const; }; template Polygon::Polygon(const BSONObj& bson) : _bson(GeoObj::validateType(bson, kPolygonTypeStr)), _linearRings(parseLinearRings(bson)), _boundingBox(Geometry::parseBoundingBox(bson)) {} template Polygon::Polygon(const std::vector >& linearRings) : _bson(createBSON(linearRings)), _linearRings(linearRings) {} template Polygon::Polygon(const Polygon& other) : _bson(other._bson), _linearRings(other._linearRings) { // TODO: consider refactoring this to not make deep copies, // and instead use a boost::shared_ptr to share the same bounding // box across all copies of a Point. This would also let the // compiler generate copy and assignment constructors, so we can drop // them from the implementation. if (other._boundingBox) _boundingBox.reset(new BoundingBox(*other._boundingBox)); } template Polygon& Polygon::operator=(Polygon other) { using std::swap; swap(_bson, other._bson); swap(_linearRings, other._linearRings); swap(_boundingBox, other._boundingBox); return *this; } template BoundingBox Polygon::getBoundingBox() const { if (!_boundingBox) _boundingBox.reset(computeBoundingBox()); return *_boundingBox.get(); } template std::vector > Polygon::getPoints() const { std::vector > allPoints, lineStringPoints; for (size_t i = 0; i < _linearRings.size(); ++i) { lineStringPoints = _linearRings[i].getPoints(); for (size_t j = 0; j < lineStringPoints.size(); ++j) allPoints.push_back(lineStringPoints[j]); } return allPoints; } template std::vector > Polygon::getLinearRings() const { return _linearRings; } template BSONObj Polygon::createBSON( const std::vector >& linearRings) { BSONArrayBuilder bab; for (size_t i = 0; i < linearRings.size(); ++i) bab.append(linearRings[i].toBSON()[kCoordsFieldName]); BSONObjBuilder bob; return bob.append(kTypeFieldName, kPolygonTypeStr).append(kCoordsFieldName, bab.arr()).obj(); } template std::vector > Polygon::parseLinearRings( const BSONObj& bson) { std::vector linearRingElems = Geometry::getCoordsField(bson).Array(); std::vector > linearRings; for (size_t i = 0; i < linearRingElems.size(); ++i) { linearRings.push_back(LineString( Geometry::parsePointArray(linearRingElems[i].Array()))); } return linearRings; } template BoundingBox* Polygon::computeBoundingBox() const { return Geometry::computeBoundingBox(getPoints()); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/geo/queryutils.h000066400000000000000000000046451273231111400232500ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/export_macros.h" #include "mongo/db/jsobj.h" #include "mongo/geo/boundingbox.h" #include "mongo/geo/constants.h" #include "mongo/geo/geoobj.h" namespace mongo { namespace geo { template inline BSONObj GEOQUERY(const char* op, const GeoObj& geoObj) { return BSON(op << BSON("$geometry" << geoObj.toBSON())); } template inline BSONObj WITHINQUERY(const GeoObj& geoObj) { return GEOQUERY("$geoWithin", geoObj); } template inline BSONObj WITHINQUERY(const BoundingBox& geoBB) { return BSON("$geoWithin" << BSON("$box" << geoBB.toNestedBSONArray())); } template inline BSONObj INTERSECTSQUERY(const GeoObj& geoObj) { return GEOQUERY("$geoIntersects", geoObj); } template inline BSONObj NEARQUERY(const GeoObj& geoObj) { return GEOQUERY("$near", geoObj); } template inline BSONObj NEARQUERY(const GeoObj& geoObj, double maxDistance) { uassert(0, "$maxDistance param to $near query must be non-negative.", maxDistance >= 0.0); return BSON("$near" << BSON("$geometry" << geoObj.toBSON() << "$maxDistance" << maxDistance)); } template inline BSONObj NEARSPHEREQUERY(const GeoObj& geoObj) { return GEOQUERY("$nearSphere", geoObj); } template inline BSONObj NEARSPHEREQUERY(const GeoObj& geoObj, double maxDistance) { uassert(0, "$maxDistance param to $nearSphere query must be non-negative.", maxDistance >= 0.0); return BSON( "$nearSphere" << BSON("$geometry" << geoObj.toBSON() << "$maxDistance" << maxDistance)); } } // namespace geo } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/000077500000000000000000000000001273231111400224115ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/data000066400000000000000000000000241273231111400232410ustar00rootroot00000000000000data in a file, wow mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/integration_test.h000066400000000000000000000066651273231111400261610ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/orchestration/replica_set.h" #include "mongo/orchestration/server.h" #include "mongo/orchestration/service.h" #include "mongo/unittest/unittest.h" // Act like we are using the driver externally #ifdef MONGO_EXPOSE_MACROS #undef MONGO_EXPOSE_MACROS #endif namespace mongo { namespace integration { // // MongoDB Integration Test Environment // // Augments the testing environment such that the orchestration service is available. // // This Environment is available globally in tests and test fixtures that use the provided // integration_test_main.cpp. // // Google test takes ownership and is responsible for destructing new heap allocated // instances of this object via AddGlobalTestEnvironment. // class Environment : public ::testing::Environment { public: Environment(const std::string& uri, const std::string& preset) { _orchestration.reset(new mongo::orchestration::Service(uri)); _preset = preset; } static const std::auto_ptr& orchestration() { return _orchestration; } static const std::string& getPreset() { return _preset; } private: static std::string _preset; static std::auto_ptr _orchestration; }; // // MongoDB Integration Test Fixture for single server ("standalone") tests // // Creates a Mongod instance which is unique per test-case and destroys it upon test // termination. // class StandaloneTest : public ::testing::Test { public: static mongo::orchestration::Server server() { return Environment::orchestration()->server(_id); } static void SetUpTestCase() { mongo::orchestration::Document params; params["preset"] = Environment::getPreset(); _id = Environment::orchestration()->createMongod(params); } static void TearDownTestCase() { Environment::orchestration()->server(_id).destroy(); } private: static std::string _id; }; // // MongoDB Integration Test Fixture for replica set tests // // Creates a Replica Set which is unique per test-case and destroys it upon test // termination. Uses the arbiter preset which creates a 3 node set with 2 data bearing // members and an arbiter. // class ReplicaSetTest : public ::testing::Test { public: static mongo::orchestration::ReplicaSet rs() { return Environment::orchestration()->replicaSet(_id); } static void SetUpTestCase() { mongo::orchestration::Document params; params["preset"] = Environment::getPreset(); _id = Environment::orchestration()->createReplicaSet(params); } static void TearDownTestCase() { Environment::orchestration()->replicaSet(_id).destroy(); } private: static std::string _id; }; } // namespace integration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/integration_test_main.cpp000066400000000000000000000034321273231111400275050ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongo/integration/integration_test.h" #include "mongo/client/init.h" namespace mongo { namespace integration { std::auto_ptr Environment::_orchestration; std::string Environment::_preset; std::string mongo::integration::StandaloneTest::_id; std::string mongo::integration::ReplicaSetTest::_id; } // namespace integration } // namespace mongo int main(int argc, char** argv) { if (!(argc == 2 || argc == 3)) { std::cout << "usage: " << argv[0] << " MONGO_ORCHESTRATION_HOST:MONGO_ORCHESTRATION_PORT" << " [MONGO_ORCHESTRATION_PRESET]" << std::endl; } mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cerr << "failed to initialize the client driver: " << instance.status() << std::endl; ::abort(); } std::string preset("basic.json"); if (argc == 3) { preset = argv[2]; } // Google test takes ownership of Environment and destroys it when finished. ::testing::AddGlobalTestEnvironment(new mongo::integration::Environment(argv[1], preset)); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/replica_set/000077500000000000000000000000001273231111400247035ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/replica_set/basic.cpp000066400000000000000000000073651273231111400265030ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/integration/integration_test.h" #include #include "mongo/client/dbclient.h" namespace { using namespace std; using namespace mongo; using namespace mongo::integration; const string TEST_NS = "test-basic.basic"; const string TEST_DB = "test-basic"; const string TEST_COLL = "basic"; class RSBasicTest : public ReplicaSetTest { public: RSBasicTest() { std::string errmsg; ConnectionString cs = ConnectionString::parse(rs().mongodbUri(), errmsg); conn.reset(static_cast(cs.connect(errmsg))); conn->dropCollection(TEST_NS); } std::auto_ptr conn; }; bool serverGTE(DBClientBase* c, int major, int minor) { BSONObj result; c->runCommand("admin", BSON("buildinfo" << true), result); std::vector version = result.getField("versionArray").Array(); int serverMajor = version[0].Int(); int serverMinor = version[1].Int(); // std::pair uses lexicographic ordering return std::make_pair(serverMajor, serverMinor) >= std::make_pair(major, minor); } TEST_F(RSBasicTest, InsertRecoversFromPrimaryFailure) { WriteConcern wcAll = WriteConcern().nodes(2).timeout(60000); conn->insert(TEST_NS, BSON("x" << 1), 0, &wcAll); orchestration::Server original_primary = rs().primary(); original_primary.stop(); while (true) { try { conn->insert(TEST_NS, BSON("x" << 2), 0, &WriteConcern::acknowledged); break; } catch (const DBException&) { mongo::sleepsecs(1); } } ASSERT_EQUALS(conn->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_EQUALS(conn->count(TEST_NS, Query("{x: 2}")), 1U); original_primary.start(); while (true) { try { conn->insert(TEST_NS, BSON("x" << 2), 0, &wcAll); break; } catch (const DBException&) { // try again mongo::sleepsecs(1); } } } TEST_F(RSBasicTest, SecondaryQueryIsNotInteruptedByPrimaryFailure) { WriteConcern wcAll = WriteConcern().nodes(2); conn->insert(TEST_NS, BSON("x" << 1), 0, &wcAll); orchestration::Server primary = rs().primary(); primary.stop(); conn->findOne(TEST_NS, Query().readPref(ReadPreference_SecondaryOnly, BSONArray())); primary.start(); } TEST_F(RSBasicTest, FindAndModifyFailure) { if (serverGTE(conn.get(), 3, 1)) { WriteConcern wcAll = WriteConcern().nodes(5).journal(true); conn->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); // findAndModify is expected to throw since we want 5 nodes, and the replica set set only // has 3 nodes ASSERT_THROWS(conn->findAndModify(TEST_NS, BSON("i" << 1), BSON("$inc" << BSON("i" << 1)), false, false, BSONObj(), BSONObj(), &wcAll), OperationException); } } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/replica_set/read_preference.cpp000066400000000000000000000221711273231111400305230ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/integration/integration_test.h" #include #include #include "mongo/client/dbclient.h" namespace { using namespace std; using namespace mongo; using namespace mongo::integration; const string TEST_NS = "test-read_pref.read_pref"; const string TEST_DB = "test-read_pref"; const string TEST_COLL = "read_pref"; class ReadPreferenceTest : public ReplicaSetTest { public: static void SetUpTestCase() { try { ReplicaSetTest::SetUpTestCase(); std::string errmsg; ConnectionString cs = ConnectionString::parse(rs().mongodbUri(), errmsg); replset_conn.reset(static_cast(cs.connect(errmsg))); replset_conn->dropCollection(TEST_NS); ConnectionString primaryCs = ConnectionString::parse(rs().primary().mongodbUri(), errmsg); primary_conn.reset(static_cast(primaryCs.connect(errmsg))); ConnectionString secondaryCs = ConnectionString::parse(rs().secondaries().front().mongodbUri(), errmsg); secondary_conn.reset(static_cast(secondaryCs.connect(errmsg))); return; } catch (const std::exception& ex) { std::cout << "Got fatal error during test setup: " << ex.what() << std::endl; } catch (...) { std::cout << "Got unknown error during test setup" << std::endl; } std::abort(); } static auto_ptr replset_conn; static auto_ptr primary_conn; static auto_ptr secondary_conn; }; auto_ptr ReadPreferenceTest::replset_conn; auto_ptr ReadPreferenceTest::primary_conn; auto_ptr ReadPreferenceTest::secondary_conn; int op_count(const auto_ptr& connection, const std::string& op_type) { BSONObj cmd = BSON("serverStatus" << 1); BSONObj info; connection->runCommand("admin", cmd, info); return info["opcounters"][op_type].Int(); } void assert_route(const auto_ptr& test_conn, const auto_ptr& expected_target, void (*op)(const auto_ptr&, ReadPreference), ReadPreference rp, const std::string& op_type) { // Prime the test connection test_conn->findOne(TEST_NS, Query().readPref(rp, BSONArray())); // Record operations of this type before running operation int ops_before = op_count(expected_target, op_type); // Run the Operation op(test_conn, rp); // Record operations of this type after running operation int ops_after = op_count(expected_target, op_type); // The serverStatus command itself adds a command to the count ASSERT_EQUALS(ops_after - ops_before, op_type == "command" ? 2 : 1); } void query(const auto_ptr& test_conn, ReadPreference rp) { Query q = Query().readPref(rp, BSONArray()); test_conn->findOne(TEST_NS, q); } BSONObj makeReadPreferenceObject(ReadPreference rp) { switch (rp) { case ReadPreference_PrimaryOnly: return BSON("mode" << "primary"); case ReadPreference_PrimaryPreferred: return BSON("mode" << "primaryPreferred"); case ReadPreference_SecondaryOnly: return BSON("mode" << "secondary"); case ReadPreference_SecondaryPreferred: return BSON("mode" << "secondaryPreferred"); case ReadPreference_Nearest: return BSON("mode" << "nearest"); default: return BSONObj(); } } BSONObj makeTestCommand(const std::string& cmdName, ReadPreference rp) { BSONObjBuilder cmd; cmd.append("query", BSON(cmdName << TEST_COLL)); cmd.append("$readPreference", makeReadPreferenceObject(rp)); return cmd.obj(); } void count(const auto_ptr& test_conn, ReadPreference rp) { BSONObj ignoredResult; test_conn->runCommand(TEST_DB, makeTestCommand("count", rp), ignoredResult); } void distinct(const auto_ptr& test_conn, ReadPreference rp) { BSONObj ignoredResult; test_conn->runCommand(TEST_DB, makeTestCommand("distinct", rp), ignoredResult); } void collStats(const auto_ptr& test_conn, ReadPreference rp) { BSONObj ignoredResult; test_conn->runCommand(TEST_DB, makeTestCommand("collStats", rp), ignoredResult); } TEST_F(ReadPreferenceTest, RoutingQuery) { assert_route(replset_conn, primary_conn, query, ReadPreference_PrimaryOnly, "query"); assert_route(replset_conn, primary_conn, query, ReadPreference_PrimaryPreferred, "query"); assert_route(replset_conn, secondary_conn, query, ReadPreference_SecondaryOnly, "query"); assert_route(replset_conn, secondary_conn, query, ReadPreference_SecondaryPreferred, "query"); } TEST_F(ReadPreferenceTest, RoutingCount) { assert_route(replset_conn, primary_conn, count, ReadPreference_PrimaryOnly, "command"); assert_route(replset_conn, primary_conn, count, ReadPreference_PrimaryPreferred, "command"); assert_route(replset_conn, secondary_conn, count, ReadPreference_SecondaryOnly, "command"); assert_route(replset_conn, secondary_conn, count, ReadPreference_SecondaryPreferred, "command"); } TEST_F(ReadPreferenceTest, RoutingDistinct) { assert_route(replset_conn, primary_conn, distinct, ReadPreference_PrimaryOnly, "command"); assert_route(replset_conn, primary_conn, distinct, ReadPreference_PrimaryPreferred, "command"); assert_route(replset_conn, secondary_conn, distinct, ReadPreference_SecondaryOnly, "command"); assert_route( replset_conn, secondary_conn, distinct, ReadPreference_SecondaryPreferred, "command"); } TEST_F(ReadPreferenceTest, RoutingCollStats) { assert_route(replset_conn, primary_conn, collStats, ReadPreference_PrimaryOnly, "command"); assert_route(replset_conn, primary_conn, collStats, ReadPreference_PrimaryPreferred, "command"); assert_route(replset_conn, secondary_conn, collStats, ReadPreference_SecondaryOnly, "command"); assert_route( replset_conn, secondary_conn, collStats, ReadPreference_SecondaryPreferred, "command"); } TEST_F(ReadPreferenceTest, RoutingPrimaryDown) { mongo::orchestration::Server primary = rs().primary(); primary.stop(); while (true) { try { replset_conn->findOne(TEST_NS, Query().readPref(ReadPreference_SecondaryOnly, BSONArray())); break; } catch (const DBException& ex) { std::cout << ex.what() << std::endl; mongo::sleepsecs(1); } } assert_route(replset_conn, secondary_conn, query, ReadPreference_PrimaryPreferred, "query"); assert_route(replset_conn, secondary_conn, query, ReadPreference_SecondaryOnly, "query"); assert_route(replset_conn, secondary_conn, query, ReadPreference_SecondaryPreferred, "query"); primary.start(); while (true) { try { WriteConcern wcAll = WriteConcern().nodes(2); replset_conn->insert(TEST_NS, BSON("x" << 2), 0, &wcAll); break; } catch (const DBException&) { mongo::sleepsecs(1); } } } TEST_F(ReadPreferenceTest, QueryPrimaryOnly) { Query q = Query().readPref(ReadPreference_PrimaryOnly, BSONArray()); auto_ptr cursor_ptr = replset_conn->query(TEST_NS, q); ASSERT_TRUE(cursor_ptr->originalHost() == replset_conn->masterConn().getServerAddress()); } TEST_F(ReadPreferenceTest, QueryPrimaryPreferred) { Query q = Query().readPref(ReadPreference_PrimaryPreferred, BSONArray()); auto_ptr cursor_ptr = replset_conn->query(TEST_NS, q); ASSERT_TRUE(cursor_ptr->originalHost() == replset_conn->masterConn().getServerAddress()); } TEST_F(ReadPreferenceTest, QuerySecondaryOnly) { Query q = Query().readPref(ReadPreference_SecondaryOnly, BSONArray()); auto_ptr cursor_ptr = replset_conn->query(TEST_NS, q); ASSERT_TRUE(cursor_ptr->originalHost() != replset_conn->masterConn().getServerAddress()); } TEST_F(ReadPreferenceTest, QuerySecondaryPreferred) { Query q = Query().readPref(ReadPreference_SecondaryPreferred, BSONArray()); auto_ptr cursor_ptr = replset_conn->query(TEST_NS, q); ASSERT_TRUE(cursor_ptr->originalHost() != replset_conn->masterConn().getServerAddress()); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/000077500000000000000000000000001273231111400245415ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/bulk_operation_test.cpp000066400000000000000000000767241273231111400313410ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/integration/integration_test.h" #include "mongo/client/command_writer.h" #include "mongo/client/dbclient.h" #include "mongo/client/write_result.h" #include "mongo/client/wire_protocol_writer.h" #include "mongo/util/stringutils.h" namespace { using std::string; using std::vector; using namespace mongo; using namespace mongo::integration; const string TEST_DB = "test-bulk_operation"; const string TEST_COLL = "bulk_operation"; const string TEST_NS = "test-bulk_operation.bulk_operation"; template struct RequiredWireVersion; template <> struct RequiredWireVersion { static const int value = 0; }; template <> struct RequiredWireVersion { static const int value = 2; }; template class BulkOperationTest : public StandaloneTest { public: BulkOperationTest() { std::string errmsg; ConnectionString cs = ConnectionString::parse(server().mongodbUri(), errmsg); c = static_cast(cs.connect(errmsg)); c->dropCollection(TEST_NS); _originalWireVersion = c->getMaxWireVersion(); c->setWireVersions(RequiredWireVersion::value, RequiredWireVersion::value); } ~BulkOperationTest() { delete c; } // Returns true if connection supports the parameterized DBClientWriter bool testSupported() { return (_originalWireVersion >= RequiredWireVersion::value); } DBClientConnection* c; int _originalWireVersion; }; typedef ::testing::Types DBClientWriters; TYPED_TEST_CASE(BulkOperationTest, DBClientWriters); TYPED_TEST(BulkOperationTest, InsertOrdered) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("a" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 1); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); BSONObj doc = this->c->findOne(TEST_NS, Query("{}")); ASSERT_EQUALS(doc["a"].numberInt(), 1); } TYPED_TEST(BulkOperationTest, InsertUnordered) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, false, false); bulk.insert(BSON("a" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 1); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); BSONObj doc = this->c->findOne(TEST_NS, Query("{}")); ASSERT_EQUALS(doc["a"].numberInt(), 1); } TYPED_TEST(BulkOperationTest, InsertBadKeyOrdered) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("$a" << 1)); WriteResult result; ASSERT_THROW(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 0U); } TYPED_TEST(BulkOperationTest, InsertBadKeyUnordered) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, false, false); bulk.insert(BSON("$a" << 1)); WriteResult result; ASSERT_THROW(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 0U); } TYPED_TEST(BulkOperationTest, UpdateOneMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).updateOne(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); } TYPED_TEST(BulkOperationTest, UpdateMultiMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).update(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 2); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 2); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1, x: 1}")), 2U); } TYPED_TEST(BulkOperationTest, UpdateAllDocuments) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(fromjson("{}")).update(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 3); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 3); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 3U); } TYPED_TEST(BulkOperationTest, ReplaceEntireDocument) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).replaceOne(BSON("x" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_FALSE(this->c->findOne(TEST_NS, Query("{x: 1}")).hasField("a")); } TYPED_TEST(BulkOperationTest, UpsertOneMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).upsert().updateOne(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, UpsertOneNotMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 2)).upsert().updateOne(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_TRUE(this->c->findOne(TEST_NS, Query("{x: 1}")).hasField("a")); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, UpsertMultiMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).upsert().update(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 2); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 2); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 2U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, UpsertMultiNotMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 2)).upsert().update(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_TRUE(this->c->findOne(TEST_NS, Query("{x: 1}")).hasField("a")); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, MultipleUpsertsMixedBatchHaveCorrectSequence) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 2)).upsert().update(BSON("$inc" << BSON("x" << 1))); bulk.find(BSON("a" << 3)).upsert().update(BSON("$inc" << BSON("x" << 1))); bulk.insert(BSON("a" << 4)); bulk.find(BSON("a" << 5)).upsert().update(BSON("$inc" << BSON("x" << 1))); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.upserted()[0].getIntField("index"), 0); ASSERT_EQUALS(result.upserted()[1].getIntField("index"), 1); ASSERT_EQUALS(result.upserted()[2].getIntField("index"), 3); } TYPED_TEST(BulkOperationTest, UpsertReplaceMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).upsert().replaceOne(BSON("x" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, UpsertReplaceNotMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 2)).upsert().replaceOne(BSON("x" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{x: 1}")), 1U); ASSERT_FALSE(this->c->findOne(TEST_NS, Query("{x: 1}")).hasField("a")); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 3U); } TYPED_TEST(BulkOperationTest, RemoveOneMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).removeOne(); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 1); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 2U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); } TYPED_TEST(BulkOperationTest, RemoveAllMatchingSelector) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("a" << 1)).remove(); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 2); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); } TYPED_TEST(BulkOperationTest, RemoveAll) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(fromjson("{}")).remove(); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_TRUE(result.upserted().empty()); ASSERT_EQUALS(result.nInserted(), 0); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 3); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{}")), 0U); } TYPED_TEST(BulkOperationTest, MultipleOrderedOperations) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("c" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("a" << 1)); bulk.insert(BSON("a" << 1)); bulk.insert(BSON("b" << 1)); bulk.find(BSON("a" << 1)).updateOne(BSON("$set" << BSON("a" << 2))); bulk.find(BSON("c" << 1)).remove(); bulk.find(BSON("_id" << 1)).upsert().update(BSON("$set" << BSON("b" << 1))); bulk.insert(BSON("b" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), 4); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 1); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_EQUALS(result.upserted().front().getIntField("index"), 5); ASSERT_EQUALS(result.upserted().front().getIntField("_id"), 1); ASSERT_FALSE(result.hasErrors()); } TYPED_TEST(BulkOperationTest, MultipleUnorderedOperations) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("c" << 1)); BulkOperationBuilder bulk(this->c, TEST_NS, false, false); bulk.insert(BSON("a" << 1)); bulk.insert(BSON("a" << 1)); bulk.insert(BSON("b" << 1)); bulk.find(BSON("a" << 1)).updateOne(BSON("$set" << BSON("a" << 2))); bulk.find(BSON("c" << 1)).remove(); bulk.find(BSON("_id" << 1)).upsert().update(BSON("$set" << BSON("b" << 1))); bulk.insert(BSON("b" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); // this test passing depends on the current unordered optimization implementation ASSERT_EQUALS(result.nInserted(), 4); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 1); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 1); ASSERT_EQUALS(result.nRemoved(), 1); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_EQUALS(result.upserted().front().getIntField("index"), 5); ASSERT_EQUALS(result.upserted().front().getIntField("_id"), 1); ASSERT_FALSE(result.hasErrors()); } TYPED_TEST(BulkOperationTest, ExceedBatchSize) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, false, false); for (int i = 0; i < this->c->getMaxWriteBatchSize() + 1; ++i) bulk.insert(BSON("a" << 1)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nInserted(), this->c->getMaxWriteBatchSize() + 1); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_TRUE(result.upserted().empty()); ASSERT_FALSE(result.hasErrors()); } TYPED_TEST(BulkOperationTest, UpdateEmpty) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).update(BSONObj()), std::exception); } TYPED_TEST(BulkOperationTest, UpdateMissingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).update(BSON("a" << 2)), std::exception); } TYPED_TEST(BulkOperationTest, UpdateOneMissingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).updateOne(BSON("a" << 2)), std::exception); } TYPED_TEST(BulkOperationTest, UpdateMixedDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("b" << 1)) .update(BSON("$set" << BSON("a" << "2") << "a" << 2)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); } TYPED_TEST(BulkOperationTest, ReplaceOneEmpty) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("b" << 1)); bulk.find(BSON("b" << 1)).replaceOne(BSONObj()); ASSERT_EQUALS(this->c->count(TEST_NS, BSON("b" << 1)), 0U); } TYPED_TEST(BulkOperationTest, ReplaceOneHavingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).replaceOne(BSON("$set" << BSON("a" << 2))), std::exception); } TYPED_TEST(BulkOperationTest, UpdateUpsertEmpty) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).upsert().update(BSONObj()), std::exception); } TYPED_TEST(BulkOperationTest, UpdateUpsertMissingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).upsert().update(BSON("a" << 2)), std::exception); } TYPED_TEST(BulkOperationTest, UpdateOneUpsertMissingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).upsert().updateOne(BSON("a" << 2)), std::exception); } TYPED_TEST(BulkOperationTest, UpdateUpsertMixedDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.find(BSON("b" << 1)) .upsert() .update(BSON("$set" << BSON("a" << "2") << "a" << 2)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); } TYPED_TEST(BulkOperationTest, ReplaceOneUpsertHavingDollarSign) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); ASSERT_THROWS(bulk.find(BSON("b" << 1)).upsert().replaceOne(BSON("$set" << BSON("a" << 2))), std::exception); } TYPED_TEST(BulkOperationTest, ReplaceOneUpsertEmpty) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("b" << 1)); bulk.find(BSON("b" << 1)).upsert().replaceOne(BSONObj()); ASSERT_EQUALS(this->c->count(TEST_NS, BSON("b" << 1)), 0U); } TYPED_TEST(BulkOperationTest, UnorderedBatchWithErrors) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); BulkOperationBuilder bulk(this->c, TEST_NS, false, false); bulk.insert(BSON("b" << 1 << "a" << 1)); // two of these upserts fail bulk.find(BSON("b" << 2)).upsert().update(BSON("$set" << BSON("a" << 1))); bulk.find(BSON("b" << 3)).upsert().update(BSON("$set" << BSON("a" << 2))); bulk.find(BSON("b" << 2)).upsert().update(BSON("$set" << BSON("a" << 1))); bulk.insert(BSON("b" << 4 << "a" << 3)); // this and / or the first insert fails: bulk.insert(BSON("b" << 5 << "a" << 1)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(result.nInserted(), 2); ASSERT_EQUALS(result.nUpserted(), 1); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 1U); ASSERT_EQUALS(result.upserted().front().getIntField("index"), 2); ASSERT_EQUALS(result.upserted().front().getField("_id").type(), 7); ASSERT_EQUALS(result.writeErrors().size(), 3U); BSONObj distinct_result; this->c->runCommand(TEST_DB, BSON("distinct" << TEST_COLL << "key" << "a"), distinct_result); std::vector distinct_a = distinct_result.getField("values").Array(); ASSERT_EQUALS(distinct_a[0].Number(), 1); ASSERT_EQUALS(distinct_a[1].Number(), 2); ASSERT_EQUALS(distinct_a[2].Number(), 3); } TYPED_TEST(BulkOperationTest, OrderedBatchWithErrors) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("b" << 1 << "a" << 1)); // one or two of these upserts fails bulk.find(BSON("b" << 2)).upsert().update(BSON("$set" << BSON("a" << 1))); bulk.find(BSON("b" << 3)).upsert().update(BSON("$set" << BSON("a" << 2))); bulk.find(BSON("b" << 2)).upsert().update(BSON("$set" << BSON("a" << 1))); bulk.insert(BSON("b" << 4 << "a" << 3)); // this and / or the first insert fails: bulk.insert(BSON("b" << 5 << "a" << 1)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(result.nInserted(), 1); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 0U); ASSERT_EQUALS(result.writeErrors().size(), 1U); BSONObj writeError = result.writeErrors().front(); ASSERT_EQUALS(writeError.getIntField("code"), 11000); ASSERT_EQUALS(writeError.getIntField("index"), 1); ASSERT_TRUE(writeError.hasField("errmsg")); // { q: { b: 2 }, u: { $set: { a: 1 } }, multi: true, upsert: true } BSONObj op = writeError.getObjectField("op"); ASSERT_EQUALS(op.getFieldDotted("q.b").Int(), 2); ASSERT_EQUALS(op.getFieldDotted("u.$set.a").Int(), 1); ASSERT_TRUE(op.getBoolField("multi")); ASSERT_TRUE(op.getBoolField("upsert")); } TYPED_TEST(BulkOperationTest, OrderedBatchSplitting) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); const int fourMb = 4 * 1024 * 1024; std::string fourMbStr; for (int i = 0; i < fourMb; ++i) fourMbStr += 'a'; for (int i = 0; i < 6; ++i) bulk.insert(BSON("_id" << i << "a" << fourMbStr.c_str())); bulk.insert(BSON("_id" << 0)); // will fail bulk.insert(BSON("_id" << 100)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(result.nInserted(), 6); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 0U); ASSERT_EQUALS(result.writeErrors().size(), 1U); BSONObj writeError = result.writeErrors().front(); ASSERT_EQUALS(writeError.getIntField("code"), 11000); ASSERT_EQUALS(writeError.getIntField("index"), 6); ASSERT_TRUE(writeError.hasField("errmsg")); ASSERT_EQUALS(this->c->count(TEST_NS, Query()), 6U); } TYPED_TEST(BulkOperationTest, UnorderedBatchSplitting) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, false, false); int fourMb = 4 * 1024 * 1024; std::string fourMbStr; for (int i = 0; i < fourMb; ++i) fourMbStr += 'a'; for (int i = 0; i < 6; ++i) bulk.insert(BSON("_id" << i << "a" << fourMbStr.c_str())); bulk.insert(BSON("_id" << 0)); // will fail bulk.insert(BSON("_id" << 100)); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(result.nInserted(), 7); ASSERT_EQUALS(result.nUpserted(), 0); ASSERT_EQUALS(result.nMatched(), 0); if (result.hasModifiedCount()) ASSERT_EQUALS(result.nModified(), 0); ASSERT_EQUALS(result.nRemoved(), 0); ASSERT_EQUALS(result.upserted().size(), 0U); ASSERT_EQUALS(result.writeErrors().size(), 1U); BSONObj writeError = result.writeErrors().front(); ASSERT_EQUALS(writeError.getIntField("code"), 11000); ASSERT_EQUALS(writeError.getIntField("index"), 6); ASSERT_TRUE(writeError.hasField("errmsg")); ASSERT_EQUALS(this->c->count(TEST_NS, Query()), 7U); } TYPED_TEST(BulkOperationTest, EmptyBatch) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), std::exception); } TYPED_TEST(BulkOperationTest, ExecuteBatchTwice) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSONObj()); WriteResult result; // First time is ok ASSERT_NO_THROW(bulk.execute(&WriteConcern::acknowledged, &result)); // Second time throws ASSERT_THROWS(bulk.execute(&WriteConcern::acknowledged, &result), std::exception); } TYPED_TEST(BulkOperationTest, W2WithOneNode) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSONObj()); WriteResult result; ASSERT_THROWS(bulk.execute(&WriteConcern::replicated, &result), std::exception); } TYPED_TEST(BulkOperationTest, WZeroWithWriteError) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); bulk.insert(BSON("_id" << 1)); bulk.insert(BSON("_id" << 1)); WriteResult result; ASSERT_NO_THROW(bulk.execute(&WriteConcern::unacknowledged, &result)); // Make sure we have done the inserts before moving on to the next test this->c->getLastError(); } // DRIVERS-151 TYPED_TEST(BulkOperationTest, ClientGeneratedUpsertId) { if (!this->testSupported()) return; BulkOperationBuilder bulk(this->c, TEST_NS, true, false); BSONObj cmdResult; this->c->runCommand("admin", BSON("buildinfo" << true), cmdResult); bulk.find(BSON("_id" << 0)).upsert().updateOne(BSON("$set" << BSON("a" << 0))); bulk.find(BSON("a" << 1)).upsert().replaceOne(BSON("_id" << 1)); if (versionCmp(cmdResult["version"].toString(), "2.6.0") >= 0) bulk.find(BSON("_id" << 3)).upsert().replaceOne(BSON("_id" << 2)); else bulk.find(BSON("_id" << 2)).upsert().replaceOne(BSON("_id" << 2)); WriteResult result; bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(result.nUpserted(), 3); ASSERT_EQUALS(result.upserted().size(), 3U); for (int i = 0; i < 3; ++i) { ASSERT_EQUALS(result.upserted()[i].getIntField("index"), i); ASSERT_EQUALS(result.upserted()[i].getIntField("_id"), i); } } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/dbclient_test.cpp000066400000000000000000001555631273231111400301070ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include #include #include #include #include #include #include #include "mongo/stdx/functional.h" #include "mongo/integration/integration_test.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/stringutils.h" #include "mongo/bson/bson.h" #include "mongo/client/dbclient.h" #include "boost/thread.hpp" using std::auto_ptr; using std::list; using std::string; using std::vector; using namespace mongo; using namespace mongo::integration; namespace { const string TEST_NS = "test-dbclient.dbclient"; const string TEST_DB = "test-dbclient"; const string TEST_COLL = "dbclient"; class DBClientTest : public StandaloneTest { public: DBClientTest() { std::string errmsg; _connStr = ConnectionString::parse(server().mongodbUri(), errmsg); c.reset(static_cast(_connStr.connect(errmsg))); c->dropCollection(TEST_NS); _uri = server().uri(); } ConnectionString _connStr; std::auto_ptr c; std::string _uri; }; bool serverGTE(DBClientBase* c, int major, int minor) { BSONObj result; c->runCommand("admin", BSON("buildinfo" << true), result); std::vector version = result.getField("versionArray").Array(); int serverMajor = version[0].Int(); int serverMinor = version[1].Int(); // std::pair uses lexicographic ordering return std::make_pair(serverMajor, serverMinor) >= std::make_pair(major, minor); } bool serverStorageEngine(DBClientBase* c, const StringData& engineName) { BSONObj result; c->runCommand("admin", BSON("serverStatus" << true), result); BSONElement storageEngineField = result.getField("storageEngine"); if (storageEngineField.eoo() || storageEngineField.type() != Object) { return engineName == "mmapv1"; } BSONElement storageEngineNameField = storageEngineField.Obj().getField("name"); if (storageEngineNameField.eoo()) { throw std::runtime_error("storageEngine object does not have field `name`"); } return engineName == storageEngineNameField.String(); } void createUser(DBClientConnection* c, const std::string& db, const string& name, const string& password) { if (serverGTE(c, 2, 6)) { BSONObj ret; ASSERT_TRUE(c->runCommand( db, BSON("createUser" << name << "pwd" << password << "roles" << BSON_ARRAY("readWrite")), ret)); } else if (serverGTE(c, 2, 4)) { ASSERT_NO_THROW( c->insert(db + ".system.users", BSON("user" << name << "pwd" << c->createPasswordDigest(name, password)))); } } #ifdef MONGO_SSL const bool kCompiledWithSSL = true; #else const bool kCompiledWithSSL = false; #endif TEST_F(DBClientTest, ByPassDocumentValidation) { if (serverGTE(c.get(), 3, 1)) { c->createCollectionWithOptions( TEST_NS, 0, false, 0, BSON("validator" << BSON("fieldName" << GTE << 1024))); ASSERT_THROWS(c->insert(TEST_NS, BSON("fieldName" << 1000)), OperationException); ASSERT_EQUALS(c->count(TEST_NS), 0U); c->insert(TEST_NS, BSON("fieldName" << 1000), InsertOption_BypassDocumentValidation); ASSERT_EQUALS(c->count(TEST_NS), 1U); // Validate we fail with ByPassDocumentValidation, and unacknowledged writes against 3.2 ASSERT_THROWS(c->insert(TEST_NS, BSON("fieldName" << 1000), InsertOption_BypassDocumentValidation, &WriteConcern::unacknowledged), std::exception); c->update(TEST_NS, BSON("fieldName" << 1000), BSON("fieldName" << 1001), UpdateOption_BypassDocumentValidation); ASSERT_THROWS(c->update(TEST_NS, BSON("fieldName" << 1001), BSON("fieldName" << 1003)), OperationException); } } TEST_F(DBClientTest, ByPassDocumentValidationBulk) { if (serverGTE(c.get(), 3, 1)) { // Note: The bulk operation tests do not set a high enough max wire version for this test to // work so this test is in this suite. c->createCollectionWithOptions( TEST_NS, 0, false, 0, BSON("validator" << BSON("fieldName" << GTE << 1024))); { BulkOperationBuilder bulk(c.get(), TEST_NS, true, false); bulk.insert(BSON("fieldName" << 1000)); WriteResult result; ASSERT_THROW(bulk.execute(&WriteConcern::acknowledged, &result), std::exception); } { BulkOperationBuilder bulk(c.get(), TEST_NS, true, true); bulk.insert(BSON("fieldName" << 1000)); WriteResult result; ASSERT_NO_THROW(bulk.execute(&WriteConcern::acknowledged, &result)); } } } TEST_F(DBClientTest, ByPassDocumentValidationFindAndModify) { if (serverGTE(c.get(), 3, 1)) { c->createCollectionWithOptions( TEST_NS, 0, false, 0, BSON("validator" << BSON("fieldName" << GTE << 1024))); c->insert(TEST_NS, BSON("_id" << 1 << "fieldName" << 1024)); ASSERT_THROWS( c->findAndModify( TEST_NS, BSON("fieldName" << 1024), BSON("$dec" << BSON("fieldName" << 1)), false), OperationException); ASSERT_THROWS(c->findAndModify(TEST_NS, BSON("fieldName" << 1024), BSON("$dec" << BSON("fieldName" << 1)), false, false, BSONObj(), BSONObj(), NULL, true), OperationException); } } /* DBClient Tests */ TEST_F(DBClientTest, Save) { // Save a doc with autogenerated id c->save(TEST_NS, BSON("hello" << "world")); BSONObj result = c->findOne(TEST_NS, Query()); BSONElement id = result.getField("_id"); ASSERT_EQUALS(id.type(), jstOID); // Save a doc with explicit id c->save(TEST_NS, BSON("_id" << "explicit_id" << "hello" << "bar")); BSONObj doc = c->findOne(TEST_NS, MONGO_QUERY("_id" << "explicit_id")); ASSERT_EQUALS(doc.getStringField("_id"), std::string("explicit_id")); ASSERT_EQUALS(doc.getStringField("hello"), std::string("bar")); // Save docs with _id field already present (shouldn't create new docs) ASSERT_EQUALS(c->count(TEST_NS), 2U); c->save(TEST_NS, BSON("_id" << id.OID() << "hello" << "world")); ASSERT_EQUALS(c->count(TEST_NS), 2U); c->save(TEST_NS, BSON("_id" << "explicit_id" << "hello" << "baz")); ASSERT_EQUALS(c->count(TEST_NS), 2U); ASSERT_EQUALS(c->findOne(TEST_NS, MONGO_QUERY("_id" << "explicit_id")).getStringField("hello"), std::string("baz")); } TEST_F(DBClientTest, FindAndModify) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 1), BSON("$inc" << BSON("i" << 1)), false); ASSERT_EQUALS(result.getIntField("_id"), 1); ASSERT_EQUALS(result.getIntField("i"), 1); ASSERT_EQUALS(c->count(TEST_NS), 1U); } TEST_F(DBClientTest, FindAndModifyNoMatch) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 2), BSON("$inc" << BSON("i" << 1)), false); ASSERT_TRUE(result.isEmpty()); ASSERT_EQUALS(c->count(TEST_NS), 1U); } TEST_F(DBClientTest, FindAndModifyNoMatchUpsert) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 2), BSON("$inc" << BSON("i" << 1)), true); ASSERT_TRUE(result.isEmpty()); ASSERT_EQUALS(c->count(TEST_NS), 2U); } TEST_F(DBClientTest, FindAndModifyReturnNew) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 1), BSON("$inc" << BSON("i" << 1)), false, true); ASSERT_EQUALS(result.getIntField("_id"), 1); ASSERT_EQUALS(result.getIntField("i"), 2); ASSERT_EQUALS(c->count(TEST_NS), 1U); } TEST_F(DBClientTest, FindAndModifyNoMatchUpsertReturnNew) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 2), BSON("$inc" << BSON("i" << 1)), true, true); ASSERT_TRUE(result.hasField("_id")); ASSERT_EQUALS(result.getIntField("i"), 3); ASSERT_EQUALS(c->count(TEST_NS), 2U); } TEST_F(DBClientTest, FindAndModifySort) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); c->insert(TEST_NS, BSON("_id" << 2 << "i" << 2)); BSONObj result = c->findAndModify( TEST_NS, BSONObj(), BSON("$inc" << BSON("i" << 1)), false, false, BSON("i" << -1)); ASSERT_EQUALS(result.getIntField("_id"), 2); ASSERT_EQUALS(result.getIntField("i"), 2); ASSERT_EQUALS(c->count(TEST_NS, BSON("_id" << 2 << "i" << 3)), 1U); } TEST_F(DBClientTest, FindAndModifyProjection) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 1), BSON("$inc" << BSON("i" << 1)), false, false, BSONObj(), BSON("_id" << 0)); ASSERT_FALSE(result.hasField("_id")); ASSERT_TRUE(result.hasField("i")); } TEST_F(DBClientTest, FindAndModifyDuplicateKeyError) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); c->createIndex(TEST_NS, IndexSpec().addKey("i").unique()); ASSERT_THROWS( c->findAndModify(TEST_NS, BSON("i" << 1 << "j" << 1), BSON("$set" << BSON("k" << 1)), true), OperationException); } TEST_F(DBClientTest, FindAndModifyWriteConcern) { if (serverGTE(c.get(), 3, 1)) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndModify(TEST_NS, BSON("i" << 1), BSON("$inc" << BSON("i" << 1)), false, false, BSONObj(), BSONObj(), &WriteConcern::journaled); ASSERT_EQUALS(result.getIntField("_id"), 1); ASSERT_EQUALS(result.getIntField("i"), 1); ASSERT_EQUALS(c->count(TEST_NS), 1U); } } TEST_F(DBClientTest, FindAndRemove) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndRemove(TEST_NS, BSON("i" << 1)); ASSERT_EQUALS(result.getIntField("_id"), 1); ASSERT_EQUALS(result.getIntField("i"), 1); ASSERT_EQUALS(c->count(TEST_NS), 0U); } TEST_F(DBClientTest, FindAndRemoveNoMatch) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndRemove(TEST_NS, BSON("i" << 2)); ASSERT_TRUE(result.isEmpty()); ASSERT_EQUALS(c->count(TEST_NS), 1U); } TEST_F(DBClientTest, FindAndRemoveSort) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); c->insert(TEST_NS, BSON("_id" << 2 << "i" << 2)); BSONObj result = c->findAndRemove(TEST_NS, BSONObj(), BSON("i" << -1)); ASSERT_EQUALS(result.getIntField("_id"), 2); ASSERT_EQUALS(result.getIntField("i"), 2); ASSERT_EQUALS(c->count(TEST_NS), 1U); ASSERT_EQUALS(c->count(TEST_NS, BSON("_id" << 1)), 1U); } TEST_F(DBClientTest, FindAndRemoveProjection) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndRemove(TEST_NS, BSON("i" << 1), BSONObj(), BSON("_id" << 0)); ASSERT_FALSE(result.hasField("_id")); ASSERT_TRUE(result.hasField("i")); ASSERT_EQUALS(c->count(TEST_NS), 0U); } TEST_F(DBClientTest, FindAndRemoveWriteConcern) { if (serverGTE(c.get(), 3, 1)) { c->insert(TEST_NS, BSON("_id" << 1 << "i" << 1)); BSONObj result = c->findAndRemove( TEST_NS, BSON("i" << 1), BSONObj(), BSONObj(), &WriteConcern::journaled); ASSERT_EQUALS(result.getIntField("_id"), 1); ASSERT_EQUALS(result.getIntField("i"), 1); ASSERT_EQUALS(c->count(TEST_NS), 0U); } } TEST_F(DBClientTest, ManualGetMore) { // Ported from dbtests/querytests.cpp for (int i = 0; i < 3; ++i) { c->insert(TEST_NS, BSON("num" << i)); } auto_ptr cursor = c->query(TEST_NS, Query("{}"), 0, 0, 0, 0, 2); uint64_t cursor_id = cursor->getCursorId(); cursor->decouple(); cursor.reset(); cursor = c->getMore(TEST_NS, cursor_id); ASSERT_TRUE(cursor->more()); ASSERT_EQUALS(cursor->next().getIntField("num"), 2); } TEST_F(DBClientTest, Distinct) { c->insert(TEST_NS, BSON("a" << 1)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 3)); BSONObj result = c->distinct(TEST_NS, "a"); std::vector results; BSONObjIterator iter(result); while (iter.more()) results.push_back(iter.next()); std::sort(results.begin(), results.end()); ASSERT_EQUALS(results[0].Int(), 1); ASSERT_EQUALS(results[1].Int(), 2); ASSERT_EQUALS(results[2].Int(), 3); } TEST_F(DBClientTest, GetCollectionInfos) { c->dropDatabase(TEST_DB); ASSERT_EQUALS(c->getCollectionNames(TEST_DB).size(), 0U); c->createCollection(TEST_DB + ".normal"); c->createCollection(TEST_DB + ".capped", 1, true); list infos = c->getCollectionInfos(TEST_DB); // Greater than because we sometimes create system.indexes, etc... ASSERT_GE(infos.size(), 2U); size_t count_non_system = 0; list::iterator it = infos.begin(); while (it != infos.end()) { BSONObj current = *it; ASSERT_TRUE(current.hasField("name")); string name = current["name"].String(); if (name == "normal") { ++count_non_system; } else if (name == "capped") { ASSERT_TRUE(current.hasField("options")); ++count_non_system; } ++it; } ASSERT_EQUALS(count_non_system, 2U); } TEST_F(DBClientTest, GetCollectionNames) { c->dropDatabase(TEST_DB); ASSERT_EQUALS(c->getCollectionNames(TEST_DB).size(), 0U); c->createCollection(TEST_DB + ".normal"); c->createCollection(TEST_DB + ".capped", 1, true); list names = c->getCollectionNames(TEST_DB); // Greater than because we sometimes create system.indexes, etc... ASSERT_GE(names.size(), 2U); list::iterator it = names.begin(); bool saw_normal = false; bool saw_capped = false; bool saw_indexes = false; while (it != names.end()) { if (*it == "normal") { ASSERT_FALSE(saw_normal); saw_normal = true; } else if (*it == "capped") { ASSERT_FALSE(saw_capped); saw_capped = true; } else { ASSERT_FALSE(saw_indexes); saw_indexes = true; } ++it; } ASSERT_TRUE(saw_normal); ASSERT_TRUE(saw_capped); } TEST_F(DBClientTest, EnumerateCollections) { const int n_collections = 9; const int batch_size = 3; for (int i = 0; i < n_collections; ++i) { std::stringstream ss; ss << TEST_DB + ".COLL" << i; c->createCollection(ss.str()); } BSONObjBuilder bob; bob.appendRegex("name", "COLL\\d$"); auto_ptr cursor = c->enumerateCollections(TEST_DB, bob.obj(), batch_size); ASSERT(cursor.get()); if (serverGTE(c.get(), 2, 8)) ASSERT_EQUALS(cursor->getns(), TEST_DB + ".$cmd.listCollections"); else ASSERT_EQUALS(cursor->getns(), TEST_DB + ".system.namespaces"); int coll_count = 0; while (cursor->more()) { // The shims don't support the objsLeftInBatch cursor interface for initial batch. // // In server versions < 2.8 we apply a transformation over the cursor to filter // out the special collections. Since we skip some results in the batch we can't // apply this test here but you can see it work with enumerateIndexes which does // not do the same transformation. if ((coll_count > batch_size) && serverGTE(c.get(), 2, 8)) ASSERT_EQUALS(cursor->objsLeftInBatch(), batch_size - (coll_count % 3)); cursor->next(); ++coll_count; } ASSERT_EQUALS(coll_count, n_collections); } TEST_F(DBClientTest, EnumerateIndexes) { const int n_indexes = 8; const int batch_size = 3; for (int i = 0; i < n_indexes; ++i) { std::stringstream ss; ss << i; c->createIndex(TEST_NS, BSON(ss.str() << 1)); } auto_ptr cursor = c->enumerateIndexes(TEST_NS, 0, batch_size); // Note: as per spec we aren't supposed to check the 2.8+ ns explicitly because it's // subject to change... but we do. If this test ever fails just safely adjust/remove. if (serverGTE(c.get(), 2, 8)) ASSERT_EQUALS(cursor->getns(), TEST_DB + ".$cmd.listIndexes." + TEST_COLL); else ASSERT_EQUALS(cursor->getns(), TEST_DB + ".system.indexes"); int index_count = 0; while (cursor->more()) { // The shims don't support the objsLeftInBatch cursor interface for initial batch. if (index_count > batch_size) ASSERT_EQUALS(cursor->objsLeftInBatch(), batch_size - (index_count % 3)); cursor->next(); ++index_count; } // _id index is there when we started so adding 1 ASSERT_EQUALS(index_count, n_indexes + 1); } TEST_F(DBClientTest, GetCollectionNamesFiltered) { c->dropDatabase(TEST_DB); ASSERT_EQUALS(c->getCollectionNames(TEST_DB).size(), 0U); c->createCollection(TEST_DB + ".normal"); c->createCollection(TEST_DB + ".capped", 1, true); list names = c->getCollectionNames(TEST_DB, BSON("options.capped" << true)); ASSERT_EQUALS(names.size(), 1U); list::iterator it = names.begin(); bool saw_capped = false; while (it != names.end()) { if (*it == "capped") { ASSERT_FALSE(saw_capped); saw_capped = true; } ++it; } ASSERT_TRUE(saw_capped); } TEST_F(DBClientTest, DistinctWithQuery) { c->insert(TEST_NS, BSON("a" << 1)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 2)); c->insert(TEST_NS, BSON("a" << 3)); BSONObj result = c->distinct(TEST_NS, "a", BSON("a" << GT << 1)); std::vector results; BSONObjIterator iter(result); while (iter.more()) results.push_back(iter.next()); std::sort(results.begin(), results.end()); ASSERT_EQUALS(results[0].Int(), 2); ASSERT_EQUALS(results[1].Int(), 3); } TEST_F(DBClientTest, DistinctDotted) { c->insert(TEST_NS, BSON("a" << BSON("b" << "a") << "c" << 12)); c->insert(TEST_NS, BSON("a" << BSON("b" << "b") << "c" << 12)); c->insert(TEST_NS, BSON("a" << BSON("b" << "c") << "c" << 12)); c->insert(TEST_NS, BSON("a" << BSON("b" << "c") << "c" << 12)); BSONObj result = c->distinct(TEST_NS, "a.b"); std::vector results; BSONObjIterator iter(result); while (iter.more()) results.push_back(iter.next()); std::sort(results.begin(), results.end()); ASSERT_EQUALS(results[0].String(), std::string("a")); ASSERT_EQUALS(results[1].String(), std::string("b")); ASSERT_EQUALS(results[2].String(), std::string("c")); } /* DBClient free functions */ TEST_F(DBClientTest, ServerAlive) { ASSERT_TRUE(serverAlive(_uri)); ASSERT_FALSE(serverAlive("mongo.example:27017")); } TEST_F(DBClientTest, ErrField) { ASSERT_FALSE(hasErrField(BSONObj())); ASSERT_TRUE(hasErrField(BSON("$err" << true))); } /* Connection level functions */ TEST_F(DBClientTest, InsertVector) { vector v; v.push_back(BSON("num" << 1)); v.push_back(BSON("num" << 2)); c->insert(TEST_NS, v); ASSERT_EQUALS(c->count(TEST_NS), 2U); } TEST_F(DBClientTest, SimpleGroup) { c->insert(TEST_NS, BSON("a" << 1 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 2 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 3 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 1 << "color" << "blue")); std::string reduce = "function(current, aggregate) {" "if (current.color === 'green') { aggregate.green++; }" "if (current.a) { aggregate.a += current.a; }" "}"; BSONObj initial = BSON("a" << 0 << "green" << 0); BSONObj cond = BSON("a" << LT << 3); BSONObj key = BSON("color" << 1); std::string finalize = "function(result) {" "result.combined = result.green + result.a;" "}"; vector results; c->group(TEST_NS, reduce, &results, initial, cond, key, finalize); vector::const_iterator it = results.begin(); while (it != results.end()) { BSONObj current = *it; if (current.getStringField("color") == std::string("green")) { ASSERT_EQUALS(current.getField("a").Double(), 3.0); ASSERT_EQUALS(current.getField("green").Double(), 2.0); ASSERT_EQUALS(current.getField("combined").Double(), 5.0); } else { ASSERT_EQUALS(current.getField("a").Double(), 1.0); ASSERT_EQUALS(current.getField("green").Double(), 0.0); ASSERT_EQUALS(current.getField("combined").Double(), 1.0); } ++it; } } TEST_F(DBClientTest, GroupWithKeyFunction) { c->insert(TEST_NS, BSON("a" << 1 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 2 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 3 << "color" << "green")); c->insert(TEST_NS, BSON("a" << 1 << "color" << "blue")); std::string reduce = "function(current, aggregate) {" "if (current.color === 'green') { aggregate.green++; }" "if (current.a) { aggregate.a += current.a; }" "}"; BSONObj initial = BSON("a" << 0 << "green" << 0); BSONObj cond = BSON("a" << LT << 3); std::string key = "function(doc) {" "return { 'color': doc.color }" "}"; std::string finalize = "function(result) {" "result.combined = result.green + result.a;" "}"; vector results; c->groupWithKeyFunction(TEST_NS, reduce, &results, initial, cond, key, finalize); vector::const_iterator it = results.begin(); while (it != results.end()) { BSONObj current = *it; if (current.getStringField("color") == std::string("green")) { ASSERT_EQUALS(current.getField("a").Double(), 3.0); ASSERT_EQUALS(current.getField("green").Double(), 2.0); ASSERT_EQUALS(current.getField("combined").Double(), 5.0); } else { ASSERT_EQUALS(current.getField("a").Double(), 1.0); ASSERT_EQUALS(current.getField("green").Double(), 0.0); ASSERT_EQUALS(current.getField("combined").Double(), 1.0); } ++it; } } void getResults(DBClientCursor* cursor, std::vector* results, boost::mutex* mut) { while (cursor->more()) { boost::lock_guard lock(*mut); results->push_back(cursor->next().getIntField("_id")); } } DBClientBase* makeNewConnection(const ConnectionString& connStr, std::vector* connectionAccumulator) { std::string errmsg; DBClientBase* newConn = static_cast(connStr.connect(errmsg)); connectionAccumulator->push_back(newConn); return newConn; } TEST_F(DBClientTest, ParallelCollectionScanUsingNewConnections) { bool supported = serverGTE(c.get(), 2, 6); if (supported) { const size_t numItems = 8000; const size_t seriesSum = (numItems * (numItems - 1)) / 2; for (size_t i = 0; i < numItems; ++i) c->insert(TEST_NS, BSON("_id" << static_cast(i))); std::vector connections; std::vector cursors; stdx::function factory = stdx::bind(&makeNewConnection, _connStr, &connections); c->parallelScan(TEST_NS, 3, &cursors, factory); std::vector results; boost::mutex resultsMutex; std::vector threads; // We can get up to 3 cursors back here but the server might give us back less for (size_t i = 0; i < cursors.size(); ++i) threads.push_back(new boost::thread(getResults, cursors[i], &results, &resultsMutex)); // Ensure all the threads have completed their scans for (size_t i = 0; i < threads.size(); ++i) { threads[i]->join(); delete threads[i]; } // Cleanup the cursors that parallel scan created for (size_t i = 0; i < cursors.size(); ++i) delete cursors[i]; // Cleanup the connections our connection factory created for (size_t i = 0; i < connections.size(); ++i) delete connections[i]; size_t sum = 0; for (size_t i = 0; i < results.size(); ++i) sum += results[i]; ASSERT_EQUALS(sum, seriesSum); } } DBClientBase* makeSketchyConnection(DBClientBase* originalConnection, std::vector* connectionAccumulator) { static int connectionCount = 0; // Fail creating the second connection DBClientConnection* newConn; if (connectionCount != 1) newConn = new DBClientConnection(); else throw OperationException(BSONObj()); newConn->connect(originalConnection->getServerAddress()); connectionAccumulator->push_back(newConn); connectionCount++; return newConn; } TEST_F(DBClientTest, ParallelCollectionScanBadConnections) { bool supported = serverGTE(c.get(), 2, 6); if (supported && serverStorageEngine(c.get(), "mmapv1")) { const size_t numItems = 8000; for (size_t i = 0; i < numItems; ++i) c->insert(TEST_NS, BSON("_id" << static_cast(i))); std::vector connections; std::vector cursors; stdx::function factory = stdx::bind(&makeSketchyConnection, c.get(), &connections); ASSERT_THROWS(c->parallelScan(TEST_NS, 3, &cursors, factory), OperationException); ASSERT_EQUALS(cursors.size(), 1U); ASSERT_EQUALS(connections.size(), 1U); // Cleanup the cursors that parallel scan created for (size_t i = 0; i < cursors.size(); ++i) delete cursors[i]; // Cleanup the connections our connection factory created for (size_t i = 0; i < connections.size(); ++i) delete connections[i]; } } TEST_F(DBClientTest, InsertVectorContinueOnError) { vector v; v.push_back(BSON("_id" << 1)); v.push_back(BSON("_id" << 1)); v.push_back(BSON("_id" << 2)); ASSERT_THROWS(c->insert(TEST_NS, v, InsertOption_ContinueOnError), OperationException); ASSERT_EQUALS(c->count(TEST_NS), 2U); } TEST_F(DBClientTest, GetIndexNames) { ASSERT_TRUE(c->getIndexNames(TEST_DB + ".fake").empty()); ASSERT_TRUE(c->getIndexNames(TEST_NS).empty()); c->insert(TEST_NS, BSON("test" << "random data")); ASSERT_EQUALS(1U, c->getIndexNames(TEST_NS).size()); c->createIndex(TEST_NS, BSON("test" << 1)); list names = c->getIndexNames(TEST_NS); ASSERT_EQUALS(2U, names.size()); ASSERT_EQUALS("_id_", names.front()); names.pop_front(); ASSERT_EQUALS("test_1", names.front()); } TEST_F(DBClientTest, GetIndexSpecs) { ASSERT_TRUE(c->getIndexSpecs(TEST_DB + ".fake").empty()); ASSERT_TRUE(c->getIndexSpecs(TEST_NS).empty()); c->insert(TEST_NS, BSON("test" << "random data")); ASSERT_EQUALS(1U, c->getIndexSpecs(TEST_NS).size()); IndexSpec spec; spec.addKey("test", IndexSpec::kIndexTypeAscending); spec.unique(true); c->createIndex(TEST_NS, spec); list specs = c->getIndexSpecs(TEST_NS); ASSERT_EQUALS(2U, specs.size()); ASSERT_EQUALS("_id_", specs.front()["name"].String()); ASSERT_EQUALS(BSON("_id" << 1), specs.front()["key"].Obj()); ASSERT_EQUALS(TEST_NS, specs.front()["ns"].String()); specs.pop_front(); ASSERT_EQUALS("test_1", specs.front()["name"].String()); ASSERT_EQUALS(BSON("test" << 1), specs.front()["key"].Obj()); ASSERT_EQUALS(TEST_NS, specs.front()["ns"].String()); ASSERT_TRUE(specs.front()["unique"].trueValue()); } TEST_F(DBClientTest, DropIndexes) { c->createIndex(TEST_NS, BSON("test" << 1)); ASSERT_EQUALS(2U, c->getIndexNames(TEST_NS).size()); c->dropIndexes(TEST_NS); ASSERT_EQUALS(1U, c->getIndexNames(TEST_NS).size()); } TEST_F(DBClientTest, DropIndex) { c->createIndex(TEST_NS, BSON("test" << 1)); c->createIndex(TEST_NS, BSON("test2" << -1)); ASSERT_EQUALS(3U, c->getIndexNames(TEST_NS).size()); // Interface that takes an index key obj c->dropIndex(TEST_NS, BSON("test" << 1)); ASSERT_EQUALS(2U, c->getIndexNames(TEST_NS).size()); // Interface that takes an index name c->dropIndex(TEST_NS, "test2_-1"); ASSERT_EQUALS(1U, c->getIndexNames(TEST_NS).size()); // Drop of unknown index should throw an error ASSERT_THROWS(c->dropIndex(TEST_NS, "test3_1"), DBException); } TEST_F(DBClientTest, ReIndex) { c->createIndex(TEST_NS, BSON("test" << 1)); c->createIndex(TEST_NS, BSON("test2" << -1)); ASSERT_EQUALS(3U, c->getIndexNames(TEST_NS).size()); c->reIndex(TEST_NS); ASSERT_EQUALS(3U, c->getIndexNames(TEST_NS).size()); } TEST_F(DBClientTest, Aggregate) { if (serverGTE(c.get(), 2, 2)) { BSONObj doc = BSON("hello" << "world"); BSONObj pipeline = BSON("0" << BSON("$match" << doc)); c->insert(TEST_NS, doc); c->insert(TEST_NS, doc); std::auto_ptr cursor = c->aggregate(TEST_NS, pipeline); ASSERT_TRUE(cursor.get()); for (int i = 0; i < 2; i++) { ASSERT_TRUE(cursor->more()); BSONObj result = cursor->next(); ASSERT_TRUE(result.valid()); ASSERT_EQUALS(result["hello"].String(), "world"); } ASSERT_FALSE(cursor->more()); } } TEST_F(DBClientTest, AggregateNoResults) { std::auto_ptr cursor = c->aggregate(TEST_NS, BSONObj()); ASSERT_TRUE(cursor.get()); ASSERT_FALSE(cursor->more()); } TEST_F(DBClientTest, CreateCollection) { ASSERT_FALSE(c->exists(TEST_NS)); ASSERT_TRUE(c->createCollection(TEST_NS)); ASSERT_FALSE(c->createCollection(TEST_NS)); ASSERT_TRUE(c->exists(TEST_NS)); BSONObj info; ASSERT_TRUE(c->runCommand(TEST_DB, BSON("collstats" << TEST_COLL), info)); bool server26plus = serverGTE(c.get(), 2, 6); if (serverGTE(c.get(), 2, 2) && serverStorageEngine(c.get(), "mmapv1")) { ASSERT_EQUALS(info.getIntField("userFlags"), server26plus ? 1 : 0); } ASSERT_EQUALS(info.getIntField("nindexes"), 1); } TEST_F(DBClientTest, CreateCollectionAdvanced) { BSONObjBuilder opts; opts.append("flags", 0); opts.append("autoIndexId", false); c->createCollectionWithOptions(TEST_NS, 1, true, 1, opts.obj()); BSONObj info; ASSERT_TRUE(c->runCommand(TEST_DB, BSON("collstats" << TEST_COLL), info)); if (serverGTE(c.get(), 2, 2) && serverStorageEngine(c.get(), "mmapv1")) { ASSERT_EQUALS(info.getIntField("userFlags"), 0); } ASSERT_EQUALS(info.getIntField("nindexes"), 0); } TEST_F(DBClientTest, CountWithHint) { c->insert(TEST_NS, BSON("a" << 1)); c->insert(TEST_NS, BSON("a" << 2)); IndexSpec normal_spec; normal_spec.addKey("a"); c->createIndex(TEST_NS, normal_spec); ASSERT_EQUALS(c->count(TEST_NS, Query("{'a': 1}").hint("_id_")), 1U); ASSERT_EQUALS(c->count(TEST_NS, Query().hint("_id_")), 2U); IndexSpec sparse_spec; sparse_spec.addKey("b").sparse(true); c->createIndex(TEST_NS, sparse_spec); Query good = Query("{'a': 1}").hint("b_1"); Query bad = Query("{'a': 1}").hint("badhint"); if (serverGTE(c.get(), 2, 6)) { ASSERT_EQUALS(c->count(TEST_NS, good), 0U); ASSERT_THROWS(c->count(TEST_NS, bad), DBException); } else { ASSERT_EQUALS(c->count(TEST_NS, good), 1U); ASSERT_NO_THROW(c->count(TEST_NS, bad)); } // In 3.3, the behavior here changed, see SERVER-22041 for details. if (serverGTE(c.get(), 3, 3)) { ASSERT_EQUALS(c->count(TEST_NS, Query().hint("b_1")), 0U); } else { ASSERT_EQUALS(c->count(TEST_NS, Query().hint("b_1")), 2U); } } TEST_F(DBClientTest, CopyDatabaseNoAuth) { c->dropDatabase("copy"); c->insert(TEST_NS, BSON("test" << true)); ASSERT_TRUE(c->copyDatabase(TEST_DB, "copy")); string copy_ns = string("copy.") + TEST_COLL; c->exists(copy_ns); BSONObj doc = c->findOne(copy_ns, Query("{}")); ASSERT_TRUE(doc["test"].boolean()); } TEST_F(DBClientTest, CopyDatabaseMONGODBCR) { // only run this test if we have auth if (serverGTE(c.get(), 2, 4) && !serverGTE(c.get(), 2, 7)) { std::string errmsg; createUser(c.get(), TEST_DB, "jane", "pwd"); ASSERT_TRUE(c->auth(TEST_DB, "jane", "pwd", errmsg)); c->dropDatabase("copy"); c->insert(TEST_NS, BSON("flavor" << "vanilla")); // NOTE: auth doesn't run if 'fromhost' is empty, because auth is // not needed to copydb locally. For testing's sake just take the // current host and use it. ASSERT_TRUE(c->copyDatabase(TEST_DB, "copy", _uri, "MONGODB-CR", "jane", "pwd")); string copy_ns = string("copy.") + TEST_COLL; c->exists(copy_ns); BSONObj doc = c->findOne(copy_ns, Query("{}")); ASSERT_TRUE(doc["flavor"].type() == String); } } TEST_F(DBClientTest, CopyDatabaseSCRAMSHA1) { // only run this test if we have SSL and a recent enough server version if (serverGTE(c.get(), 2, 7)) { if (kCompiledWithSSL) { createUser(c.get(), TEST_DB, "jane", "pwd"); std::string errmsg; ASSERT_TRUE(c->auth(TEST_DB, "jane", "pwd", errmsg)); c->dropDatabase("copy"); c->insert(TEST_NS, BSON("flavor" << "vanilla")); ASSERT_TRUE(c->copyDatabase(TEST_DB, "copy", _uri, "SCRAM-SHA-1", "jane", "pwd")); string copy_ns = string("copy.") + TEST_COLL; c->exists(copy_ns); BSONObj doc = c->findOne(copy_ns, Query("{}")); ASSERT_TRUE(doc["flavor"].type() == String); } else { ASSERT_THROWS(c->copyDatabase(TEST_DB, "copy", _uri, "SCRAM-SHA-1", "user", "pass"), UserException); } } } TEST_F(DBClientTest, CopyDatabaseInvalidMechanism) { ASSERT_THROWS(c->copyDatabase(TEST_DB, "copy", _uri, "BLOOP", "user", "pass"), UserException); } TEST_F(DBClientTest, DBProfilingLevel) { DBClientWithCommands::ProfilingLevel level; ASSERT_TRUE(c->setDbProfilingLevel(TEST_DB, c->ProfileAll)); ASSERT_TRUE(c->getDbProfilingLevel(TEST_DB, level, 0)); ASSERT_EQUALS(level, c->ProfileAll); ASSERT_TRUE(c->setDbProfilingLevel(TEST_DB, c->ProfileSlow)); ASSERT_TRUE(c->getDbProfilingLevel(TEST_DB, level, 0)); ASSERT_EQUALS(level, c->ProfileSlow); ASSERT_TRUE(c->setDbProfilingLevel(TEST_DB, c->ProfileOff)); ASSERT_TRUE(c->getDbProfilingLevel(TEST_DB, level, 0)); ASSERT_EQUALS(level, c->ProfileOff); } TEST_F(DBClientTest, QueryJSON) { Query q(string("{name: 'Tyler'}")); BSONObj filter = q.getFilter(); ASSERT_TRUE(filter.hasField("name")); ASSERT_EQUALS(filter["name"].String(), "Tyler"); } // Used to test exhaust via query below void nop(const BSONObj&) { /* nop */ } // This also excercises availableOptions (which is protected) TEST_F(DBClientTest, Exhaust) { for (int i = 0; i < 1000; ++i) c->insert(TEST_NS, BSON("num" << i)); stdx::function f = nop; c->query(f, TEST_NS, Query("{}")); } TEST_F(DBClientTest, GetPrevError) { c->insert(TEST_NS, BSON("_id" << 1)); ASSERT_THROWS(c->insert(TEST_NS, BSON("_id" << 1)), OperationException); c->insert(TEST_NS, BSON("_id" << 2)); ASSERT_TRUE(c->getLastError().empty()); ASSERT_FALSE(c->getPrevError().isEmpty()); } TEST_F(DBClientTest, MaxScan) { for (int i = 0; i < 100; ++i) { c->insert(TEST_NS, fromjson("{}")); } vector results; c->findN(results, TEST_NS, Query("{}"), 100); ASSERT_EQUALS(results.size(), 100U); results.clear(); c->findN(results, TEST_NS, Query("{$query: {}, $maxScan: 50}"), 100); ASSERT_EQUALS(results.size(), 50U); } TEST_F(DBClientTest, ReturnKey) { c->insert(TEST_NS, BSON("a" << true << "b" << true)); BSONObj result; result = c->findOne(TEST_NS, Query("{$query: {a: true}}")); ASSERT_TRUE(result.hasField("a")); ASSERT_TRUE(result.hasField("b")); result = c->findOne(TEST_NS, Query("{$query: {a: true}, $returnKey: true}")); ASSERT_FALSE(result.hasField("a")); ASSERT_FALSE(result.hasField("b")); c->createIndex(TEST_NS, BSON("a" << 1)); result = c->findOne(TEST_NS, Query("{$query: {a: true}, $returnKey: true}")); ASSERT_TRUE(result.hasField("a")); ASSERT_FALSE(result.hasField("b")); } TEST_F(DBClientTest, ShowDiskLoc) { if (!serverGTE(c.get(), 3, 1)) { c->insert(TEST_NS, BSON("a" << true)); BSONObj result; result = c->findOne(TEST_NS, Query("{$query: {}}")); ASSERT_FALSE(result.hasField("$diskLoc")); result = c->findOne(TEST_NS, Query("{$query: {}, $showDiskLoc: true}")); ASSERT_TRUE(result.hasField("$diskLoc")); } } TEST_F(DBClientTest, MaxTimeMS) { // Requires --setParameter=enableTestCommands=1 c->insert(TEST_NS, BSON("a" << true)); BSONObj result; // Use a dummy query in order to check if maxTimeMs() is correctly applied Query dummyQuery("{}"); ASSERT_FALSE(dummyQuery.hasMaxTimeMs()); ASSERT_EQUALS(&dummyQuery.maxTimeMs(10), &dummyQuery); ASSERT_TRUE(dummyQuery.hasMaxTimeMs()); ASSERT_EQUALS(dummyQuery.getMaxTimeMs(), 10); if (serverGTE(c.get(), 2, 6)) { c->runCommand("admin", BSON("configureFailPoint" << "maxTimeAlwaysTimeOut" << "mode" << BSON("times" << 2)), result); Query query = Query("{}"); Query query_max_time = Query("{}").maxTimeMs(1); // Check the boolean method ASSERT_FALSE(query.hasMaxTimeMs()); ASSERT_TRUE(query_max_time.hasMaxTimeMs()); // Check the getter ASSERT_EQUALS(query_max_time.getMaxTimeMs(), 1); // First test with a query ASSERT_NO_THROW(c->findOne(TEST_NS, query);); ASSERT_THROWS(c->findOne(TEST_NS, query_max_time), DBException); // Then test with a command ASSERT_NO_THROW(c->count(TEST_NS, query)); ASSERT_THROWS(c->count(TEST_NS, query_max_time), DBException); } else { // we are not connected to MongoDB >= 2.6, skip SUCCEED(); } } TEST_F(DBClientTest, Comment) { c->insert(TEST_NS, BSON("a" << true)); string profile_coll = TEST_DB + ".system.profile"; c->dropCollection(profile_coll); c->setDbProfilingLevel(TEST_DB, c->ProfileAll); c->findOne(TEST_NS, Query("{$query: {a: 'z'}, $comment: 'wow'})")); c->setDbProfilingLevel(TEST_DB, c->ProfileOff); BSONObj result; if (serverGTE(c.get(), 3, 1)) { result = c->findOne(profile_coll, BSON("ns" << TEST_NS << "op" << "query" << "query.comment" << "wow")); } else { result = c->findOne(profile_coll, BSON("ns" << TEST_NS << "op" << "query" << "query.$comment" << "wow")); } ASSERT_FALSE(result.isEmpty()); } TEST_F(DBClientTest, LazyCursor) { c->insert(TEST_NS, BSON("test" << true)); DBClientCursor cursor(c.get(), TEST_NS, Query("{}").obj, 0, 0, 0, 0, 0); bool is_retry = false; cursor.initLazy(is_retry); ASSERT_TRUE(cursor.initLazyFinish(is_retry)); vector docs; while (cursor.more()) docs.push_back(cursor.next()); ASSERT_EQUALS(docs.size(), 1U); ASSERT_TRUE(docs.front()["test"].value()); } void nop_hook(BSONObjBuilder* bob) { (void)bob; } void nop_hook_post(BSONObj, string) {} TEST_F(DBClientTest, LazyCursorCommand) { c->setRunCommandHook(nop_hook); c->setPostRunCommandHook(nop_hook_post); DBClientCursor cursor(c.get(), TEST_DB + ".$cmd", Query("{dbStats: 1}").obj, 1, 0, 0, 0, 0); bool is_retry = false; cursor.initLazy(is_retry); ASSERT_TRUE(cursor.initLazyFinish(is_retry)); ASSERT_TRUE(cursor.more()); ASSERT_TRUE(cursor.next().hasField("db")); ASSERT_FALSE(cursor.more()); } TEST_F(DBClientTest, InitCommand) { DBClientCursor cursor(c.get(), TEST_DB + ".$cmd", Query("{dbStats: 1}").obj, 1, 0, 0, 0, 0); ASSERT_TRUE(cursor.initCommand()); ASSERT_TRUE(cursor.more()); ASSERT_TRUE(cursor.next().hasField("db")); ASSERT_FALSE(cursor.more()); } TEST_F(DBClientTest, GetMoreLimit) { c->insert(TEST_NS, BSON("num" << 1)); c->insert(TEST_NS, BSON("num" << 2)); c->insert(TEST_NS, BSON("num" << 3)); c->insert(TEST_NS, BSON("num" << 4)); // set nToReturn to 3 but batch size to 1 // This verifies: // * we can manage with multiple batches // * we can correctly upgrade batchSize 1 to 2 to avoid automatic // cursor closing when nReturn = 1 (wire protocol edge case) auto_ptr cursor = c->query(TEST_NS, Query("{}"), 3, 0, 0, 0, 1); vector docs; while (cursor->more()) docs.push_back(cursor->next()); ASSERT_EQUALS(docs.size(), 3U); } TEST_F(DBClientTest, NoGetMoreLimit) { c->insert(TEST_NS, BSON("num" << 1)); c->insert(TEST_NS, BSON("num" << 2)); c->insert(TEST_NS, BSON("num" << 3)); c->insert(TEST_NS, BSON("num" << 4)); // set nToReturn to 2 but batch size to 4 // check to see if a limit of 2 takes despite the larger batch auto_ptr cursor = c->query(TEST_NS, Query("{}"), 2, 0, 0, 0, 4); vector docs; while (cursor->more()) docs.push_back(cursor->next()); ASSERT_EQUALS(docs.size(), 2U); } TEST_F(DBClientTest, PeekError) { BSONObj result; c->runCommand("admin", BSON("buildinfo" << true), result); // TODO: figure out if we can come up with query that produces $err on 2.4.x if (versionCmp(result["version"].toString(), "2.5.3") >= 0) { auto_ptr cursor = c->query(TEST_NS, Query("{'$fake': true}")); ASSERT_TRUE(cursor->peekError()); } else { SUCCEED(); } } TEST_F(DBClientTest, DefaultWriteConcernInsert) { c->insert(TEST_NS, BSON("_id" << 1)); ASSERT_THROWS(c->insert(TEST_NS, BSON("_id" << 1)), OperationException); ASSERT_EQUALS(c->count(TEST_NS, BSON("_id" << 1)), 1U); } TEST_F(DBClientTest, DefaultWriteConcernUpdate) { c->insert(TEST_NS, BSON("a" << true)); ASSERT_THROWS(c->update(TEST_NS, BSON("a" << true), BSON("$badOp" << "blah")), OperationException); ASSERT_EQUALS(c->count(TEST_NS, BSON("a" << true)), 1U); } TEST_F(DBClientTest, DefaultWriteConcernRemove) { ASSERT_THROWS(c->remove("BAD.$NS", BSON("a" << true)), OperationException); } TEST_F(DBClientTest, UnacknowledgedInsert) { c->insert(TEST_NS, BSON("_id" << 1)); ASSERT_NO_THROW(c->insert(TEST_NS, BSON("_id" << 1), 0, &WriteConcern::unacknowledged)); ASSERT_EQUALS(c->count(TEST_NS, BSON("_id" << 1)), 1U); } TEST_F(DBClientTest, UnacknowledgedUpdate) { c->insert(TEST_NS, BSON("a" << true)); ASSERT_NO_THROW(c->update(TEST_NS, BSON("a" << true), BSON("$badOp" << "blah"), false, false, &WriteConcern::unacknowledged)); ASSERT_EQUALS(c->count(TEST_NS, BSON("a" << true)), 1U); } TEST_F(DBClientTest, UnacknowledgedRemove) { ASSERT_NO_THROW(c->remove("BAD.$NS", BSON("a" << true), false, &WriteConcern::unacknowledged)); } TEST_F(DBClientTest, AcknowledgeMultipleNodesNonReplicated) { WriteConcern wc = WriteConcern().nodes(2).timeout(3000); ASSERT_THROWS(c->insert(TEST_NS, BSON("_id" << 1), 0, &wc), OperationException); } TEST_F(DBClientTest, CreateSimpleV0Index) { if (serverStorageEngine(c.get(), "mmapv1") && !serverGTE(c.get(), 3, 1)) { c->createIndex(TEST_NS, IndexSpec().addKey("aField").version(0)); } } TEST_F(DBClientTest, CreateSimpleNamedV0Index) { if (serverStorageEngine(c.get(), "mmapv1") && !serverGTE(c.get(), 3, 1)) { c->createIndex(TEST_NS, IndexSpec().addKey("aField").version(0).name("aFieldV0Index")); } } TEST_F(DBClientTest, CreateCompoundNamedV0Index) { if (serverStorageEngine(c.get(), "mmapv1") && !serverGTE(c.get(), 3, 1)) { c->createIndex(TEST_NS, IndexSpec() .addKey("aField") .addKey("bField", IndexSpec::kIndexTypeDescending) .version(0) .name("aFieldbFieldV0Index")); } } TEST_F(DBClientTest, CreateSimpleV1Index) { c->createIndex(TEST_NS, IndexSpec().addKey("aField").version(1)); } TEST_F(DBClientTest, CreateSimpleNamedV1Index) { c->createIndex(TEST_NS, IndexSpec().addKey("aField").version(1).name("aFieldV1Index")); } TEST_F(DBClientTest, CreateCompoundNamedV1Index) { c->createIndex(TEST_NS, IndexSpec() .addKey("aField") .addKey("bField", IndexSpec::kIndexTypeDescending) .version(1) .name("aFieldbFieldV1Index")); } TEST_F(DBClientTest, CreateUniqueSparseDropDupsIndexInBackground) { c->createIndex( TEST_NS, IndexSpec().addKey("aField").background().unique().sparse().dropDuplicatesDeprecated()); } TEST_F(DBClientTest, CreateComplexTextIndex) { if (!serverGTE(c.get(), 2, 6)) { BSONObj result; c->runCommand("admin", BSON("setParameter" << 1 << "textSearchEnabled" << true), result); } c->createIndex(TEST_NS, IndexSpec() .addKey("aField", IndexSpec::kIndexTypeText) .addKey("bField", IndexSpec::kIndexTypeText) .textWeights(BSON("aField" << 100)) .textDefaultLanguage("spanish") .textLanguageOverride("lang") .textIndexVersion(serverGTE(c.get(), 2, 6) ? 2 : 1)); } TEST_F(DBClientTest, Create2DIndex) { c->createIndex(TEST_NS, IndexSpec() .addKey("aField", IndexSpec::kIndexTypeGeo2D) .geo2DBits(20) .geo2DMin(-120.0) .geo2DMax(120.0)); } TEST_F(DBClientTest, CreateHaystackIndex) { c->createIndex(TEST_NS, IndexSpec() .addKey("aField", IndexSpec::kIndexTypeGeoHaystack) .addKey("otherField", IndexSpec::kIndexTypeDescending) .geoHaystackBucketSize(1.0)); } TEST_F(DBClientTest, Create2DSphereIndex) { c->createIndex(TEST_NS, IndexSpec() .addKey("aField", IndexSpec::kIndexTypeGeo2DSphere) .geo2DSphereIndexVersion(serverGTE(c.get(), 2, 6) ? 2 : 1)); } TEST_F(DBClientTest, CreateHashedIndex) { c->createIndex(TEST_NS, IndexSpec().addKey("aField", IndexSpec::kIndexTypeHashed)); } TEST_F(DBClientTest, CreatePartialIndex) { if (serverGTE(c.get(), 3, 1)) { c->createIndex( TEST_NS, IndexSpec().addKey("aField").partialFilterExpression(BSON("aField" << GT << 5))); std::list indexes = c->getIndexSpecs(TEST_NS); ASSERT_EQUALS(2U, indexes.size()); indexes.pop_front(); ASSERT_EQUALS(BSON("aField" << GT << 5), indexes.front()["partialFilterExpression"].Obj()); } } TEST_F(DBClientTest, CreateUser) { createUser(c.get(), TEST_DB, "user1", "password1"); } // This test would fail against a fresh 2.8 if we did not use the SCRAM-SHA-1 auth mechanism TEST_F(DBClientTest, AuthenticateUserSuccess) { /* Run this test if version indicates that the server supports auth, and we can * communicate with it. The server must be at least as new as 2.4, when auth was * introduced. If the server is as new as 2.8, then the driver must have SSL support, * to use the SCRAM-SHA-1 auth mechanism which it will likely require. */ if (serverGTE(c.get(), 2, 4) && (!serverGTE(c.get(), 2, 7) || kCompiledWithSSL)) { createUser(c.get(), TEST_DB, "user2", "password2"); std::string errmsg; ASSERT_TRUE(c->auth(TEST_DB, "user2", "password2", errmsg)); } } TEST_F(DBClientTest, AuthenticateUserFailure) { // Run test if the server can be authed into, as per AuthenticateUserSuccess if (serverGTE(c.get(), 2, 4) && (!serverGTE(c.get(), 2, 7) || kCompiledWithSSL)) { createUser(c.get(), TEST_DB, "user3", "password3"); std::string errmsg; ASSERT_FALSE(c->auth(TEST_DB, "user3", "notPassword3", errmsg)); } } TEST_F(DBClientTest, ConnectionStringWithNoDB) { if (serverGTE(c.get(), 2, 4) && (!serverGTE(c.get(), 2, 7) || kCompiledWithSSL)) { createUser(c.get(), "admin", "user4", "password4"); std::string url = "mongodb://user4:password4@" + _uri; std::string error; ConnectionString connString = ConnectionString::parse(url, error); ASSERT_TRUE(error.empty()); ASSERT_NO_THROW(connString.connect(url)); } } TEST_F(DBClientTest, ConnectionStringWithTestDB) { if (serverGTE(c.get(), 2, 4) && (!serverGTE(c.get(), 2, 7) || kCompiledWithSSL)) { createUser(c.get(), TEST_DB, "user5", "password5"); std::string url = "mongodb://user5:password5@" + _uri + "/" + TEST_DB; std::string error; ConnectionString connString = ConnectionString::parse(url, error); ASSERT_TRUE(error.empty()); ASSERT_NO_THROW(connString.connect(url)); } } std::size_t cursorCount(DBClientCursor* cursor) { std::size_t count = 0; while (cursor->more()) { cursor->nextSafe(); ++count; } return count; } TEST_F(DBClientTest, LimitWithMultipleBatches) { // We need to insert enough documents in to our collection such that we can require multiple // batches to fill our limit. std::size_t totalInserts = 25000; std::size_t bulkSize = 1000; for (std::size_t i = 0; i < totalInserts; i += bulkSize) { BulkOperationBuilder bulk(c.get(), TEST_NS, false, false); WriteResult result; for (std::size_t j = 0; j < bulkSize; ++j) { bulk.insert(BSON("i" << static_cast(i) << "j" << static_cast(j) << "a" << "bbbbbbbbbbbbbbbbbbbbbbbbbb" << "c" << "dddddddddddddddddddddddddddd")); } bulk.execute(&WriteConcern::acknowledged, &result); ASSERT_EQUALS(static_cast(result.nInserted()), bulkSize); } { // A sanity check. auto_ptr limitQuery1 = c->query(TEST_NS, mongo::Query("{}"), 1); ASSERT_EQUALS(cursorCount(limitQuery1.get()), 1u); } { // One more sanity check. auto_ptr limitQuery2 = c->query(TEST_NS, mongo::Query("{}"), 101); ASSERT_EQUALS(cursorCount(limitQuery2.get()), 101u); } { auto_ptr limitQuery3 = c->query(TEST_NS, mongo::Query("{}"), 9000); ASSERT_EQUALS(cursorCount(limitQuery3.get()), 9000u); } { auto_ptr limitQuery4 = c->query(TEST_NS, mongo::Query("{}"), 6000); ASSERT_EQUALS(cursorCount(limitQuery4.get()), 6000u); } { auto_ptr limitQuery5 = c->query(TEST_NS, mongo::Query("{}"), 15000); ASSERT_EQUALS(cursorCount(limitQuery5.get()), 15000u); } { auto_ptr limitQuery6 = c->query(TEST_NS, mongo::Query("{}"), 24999); ASSERT_EQUALS(cursorCount(limitQuery6.get()), 24999u); } { // Try with nToReturn 24999, batchSize 5 auto_ptr limitQuery6 = c->query(TEST_NS, mongo::Query("{}"), 24999, 0, 0, 0, 5); ASSERT_EQUALS(cursorCount(limitQuery6.get()), 24999u); } { // Try with nToReturn 1, batchSize 5 auto_ptr limitQuery6 = c->query(TEST_NS, mongo::Query("{}"), 1, 0, 0, 0, 5); ASSERT_EQUALS(cursorCount(limitQuery6.get()), 1u); } { // Try with nToReturn 10000, batchSize 4 auto_ptr limitQuery6 = c->query(TEST_NS, mongo::Query("{}"), 10000, 0, 0, 0, 4); ASSERT_EQUALS(cursorCount(limitQuery6.get()), 10000u); } { // Try with nToReturn 23000, batchSize 10000 auto_ptr limitQuery6 = c->query(TEST_NS, mongo::Query("{}"), 23000, 0, 0, 0, 10000); ASSERT_EQUALS(cursorCount(limitQuery6.get()), 23000u); } } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/dbclient_writer_test.cpp000066400000000000000000000404661273231111400314760ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/integration/integration_test.h" #include "mongo/client/command_writer.h" #include "mongo/client/dbclient.h" #include "mongo/client/delete_write_operation.h" #include "mongo/client/insert_write_operation.h" #include "mongo/client/update_write_operation.h" #include "mongo/client/wire_protocol_writer.h" #include "mongo/client/write_result.h" using std::string; using std::vector; using namespace mongo; using namespace mongo::integration; namespace { const string TEST_NS = "test.dbclient_writer"; template struct RequiredWireVersion; template <> struct RequiredWireVersion { static const int value = 0; }; template <> struct RequiredWireVersion { static const int value = 2; }; template class DBClientWriterTest : public StandaloneTest { public: DBClientWriterTest() { std::string errmsg; ConnectionString connStr = ConnectionString::parse(server().mongodbUri(), errmsg); c.reset(static_cast(connStr.connect(errmsg))); c->dropCollection(TEST_NS); writer = new T(c.get()); } ~DBClientWriterTest() { delete writer; } // Returns true if connection supports the parameterized DBClientWriter bool testSupported() { return (c->getMaxWireVersion() >= RequiredWireVersion::value); } DBClientWriter* writer; std::auto_ptr c; }; typedef ::testing::Types DBClientWriters; TYPED_TEST_CASE(DBClientWriterTest, DBClientWriters); TYPED_TEST(DBClientWriterTest, SingleInsert) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert(BSON("a" << 1)); inserts.push_back(&insert); WriteResult result; this->writer->write(TEST_NS, inserts, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->findOne(TEST_NS, Query())["a"].numberInt(), 1); } TYPED_TEST(DBClientWriterTest, MultipleOrderedInserts) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("a" << 1)); InsertWriteOperation insert2(BSON("a" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; this->writer->write(TEST_NS, inserts, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_FALSE(result.hasErrors()); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedInserts) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("a" << 1)); InsertWriteOperation insert2(BSON("a" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; this->writer->write(TEST_NS, inserts, false, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_FALSE(result.hasErrors()); } TYPED_TEST(DBClientWriterTest, MultipleOrderedInsertsWithError) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("_id" << 1)); InsertWriteOperation insert2(BSON("_id" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; ASSERT_THROWS( this->writer->write(TEST_NS, inserts, true, false, &WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 2}")), 0U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedInsertsWithError) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("_id" << 1)); InsertWriteOperation insert2(BSON("_id" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; ASSERT_THROWS( this->writer->write(TEST_NS, inserts, false, false, &WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleOrderedInsertsWithErrorNoConcern) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("_id" << 1)); InsertWriteOperation insert2(BSON("_id" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; this->writer->write(TEST_NS, inserts, true, false, &WriteConcern::unacknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 2}")), 0U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedInsertsWithErrorNoConcern) { if (!this->testSupported()) return; vector inserts; InsertWriteOperation insert1(BSON("_id" << 1)); InsertWriteOperation insert2(BSON("_id" << 2)); inserts.push_back(&insert1); inserts.push_back(&insert1); inserts.push_back(&insert2); WriteResult result; this->writer->write(TEST_NS, inserts, false, false, &WriteConcern::unacknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{_id: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, SingleUpdate) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); vector updates; UpdateWriteOperation update(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); updates.push_back(&update); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, SingleMultiUpdate) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 1)); vector updates; UpdateWriteOperation update(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), UpdateOption_Multi); updates.push_back(&update); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 2U); } TYPED_TEST(DBClientWriterTest, SingleUpsertDoesUpdate) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 2)); vector updates; UpdateWriteOperation update( BSON("a" << 1), BSON("$set" << BSON("a" << 2)), UpdateOption_Upsert); updates.push_back(&update); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 2U); } TYPED_TEST(DBClientWriterTest, SingleUpsertDoesUpsert) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 2)); vector updates; UpdateWriteOperation update( BSON("a" << 3), BSON("$set" << BSON("a" << 2)), UpdateOption_Upsert); updates.push_back(&update); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 2U); } TYPED_TEST(DBClientWriterTest, MultipleOrderedUpdates) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("b" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedUpdates) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("b" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; this->writer->write(TEST_NS, updates, false, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleOrderedUpdatesWithError) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("a" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; ASSERT_THROWS( this->writer->write(TEST_NS, updates, true, false, &WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedUpdatesWithError) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("a" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; ASSERT_THROWS( this->writer->write(TEST_NS, updates, false, false, &WriteConcern::acknowledged, &result), OperationException); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleOrderedUpdatesWithErrorNoConcern) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("a" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; this->writer->write(TEST_NS, updates, true, false, &WriteConcern::unacknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedUpdatesWithErrorNoConcern) { if (!this->testSupported()) return; this->c->createIndex(TEST_NS, IndexSpec().addKeys(BSON("a" << 1)).unique()); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector updates; UpdateWriteOperation updateA(BSON("a" << 1), BSON("$set" << BSON("a" << 2)), 0); UpdateWriteOperation updateB(BSON("b" << 1), BSON("$set" << BSON("a" << 2)), 0); updates.push_back(&updateA); updates.push_back(&updateB); WriteResult result; this->writer->write(TEST_NS, updates, false, false, &WriteConcern::unacknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); } TYPED_TEST(DBClientWriterTest, SingleDelete) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 0)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 2)); vector deletes; DeleteWriteOperation delete_op(BSON("a" << BSON("$gt" << 0)), 0); deletes.push_back(&delete_op); WriteResult result; this->writer->write(TEST_NS, deletes, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 0}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 0U); } TYPED_TEST(DBClientWriterTest, SingleDeleteJustOne) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 0)); this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("a" << 2)); vector deletes; DeleteWriteOperation delete_op(BSON("a" << BSON("$gt" << 0)), RemoveOption_JustOne); deletes.push_back(&delete_op); WriteResult result; this->writer->write(TEST_NS, deletes, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 0}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 2}")), 1U); } TYPED_TEST(DBClientWriterTest, MultipleOrderedDeletes) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector deletes; DeleteWriteOperation deleteA(BSON("a" << 1), 0); DeleteWriteOperation deleteB(BSON("b" << 1), 0); deletes.push_back(&deleteA); deletes.push_back(&deleteB); WriteResult result; ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); this->writer->write(TEST_NS, deletes, true, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 0U); } TYPED_TEST(DBClientWriterTest, MultipleUnorderedDeletes) { if (!this->testSupported()) return; this->c->insert(TEST_NS, BSON("a" << 1)); this->c->insert(TEST_NS, BSON("b" << 1)); vector deletes; DeleteWriteOperation deleteA(BSON("a" << 1), 0); DeleteWriteOperation deleteB(BSON("b" << 1), 0); deletes.push_back(&deleteA); deletes.push_back(&deleteB); WriteResult result; ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 1U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 1U); this->writer->write(TEST_NS, deletes, false, false, &WriteConcern::acknowledged, &result); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{a: 1}")), 0U); ASSERT_EQUALS(this->c->count(TEST_NS, Query("{b: 1}")), 0U); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/gridfs_test.cpp000066400000000000000000000203471273231111400275700ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include #include #include #include "mongo/integration/integration_test.h" #include "mongo/client/dbclient.h" using boost::scoped_ptr; using std::auto_ptr; using std::ios; using std::ifstream; using std::min; using std::string; using std::stringstream; using namespace mongo; using namespace mongo::integration; namespace { const unsigned int UDEFAULT_CHUNK_SIZE = 255 * 1024; const int DEFAULT_CHUNK_SIZE = UDEFAULT_CHUNK_SIZE; const string TEST_DB = "gridfs-test"; const char DATA_NAME[] = "data.txt"; const char OTHER_NAME[] = "other.txt"; const char DATA[] = "this is the data"; const char OTHER[] = "this is other data"; const unsigned int UDATA_LEN = 16; const unsigned int UOTHER_LEN = 18; const int DATA_LEN = UDATA_LEN; const int OTHER_LEN = UOTHER_LEN; const char DATA_LOC[] = "./src/mongo/integration/data"; class GridFSTest : public StandaloneTest { public: GridFSTest() { std::string errmsg; ConnectionString connStr = ConnectionString::parse(server().mongodbUri(), errmsg); _conn.reset(static_cast(connStr.connect(errmsg))); _conn->dropDatabase(TEST_DB); _gfs.reset(new GridFS(*_conn, TEST_DB)); } protected: scoped_ptr _conn; scoped_ptr _gfs; }; TEST_F(GridFSTest, DefaultChunkSize) { ASSERT_EQUALS(_gfs->getChunkSize(), UDEFAULT_CHUNK_SIZE); } TEST_F(GridFSTest, ModifyChunkSize) { _gfs->setChunkSize(1234U); ASSERT_EQUALS(_gfs->getChunkSize(), 1234U); } TEST_F(GridFSTest, StoreFile) { BSONObj result; result = _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); ASSERT_EQUALS(result["filename"].str(), DATA_NAME); ASSERT_EQUALS(result["length"].numberInt(), DATA_LEN); ASSERT_EQUALS(result["chunkSize"].numberInt(), DEFAULT_CHUNK_SIZE); ASSERT_TRUE(result.hasField("uploadDate")); ASSERT_TRUE(result.hasField("md5")); ASSERT_TRUE(result.hasField("_id")); } TEST_F(GridFSTest, StoreFileFromFile) { BSONObj result; ifstream dataFile(DATA_LOC); dataFile.seekg(0, std::ios_base::end); int fileSize = dataFile.tellg(); result = _gfs->storeFile(DATA_LOC, DATA_NAME); ASSERT_EQUALS(result["filename"].str(), DATA_NAME); ASSERT_EQUALS(result["length"].numberInt(), fileSize); ASSERT_EQUALS(result["chunkSize"].numberInt(), DEFAULT_CHUNK_SIZE); ASSERT_TRUE(result.hasField("uploadDate")); ASSERT_TRUE(result.hasField("md5")); ASSERT_TRUE(result.hasField("_id")); } TEST_F(GridFSTest, StoreFileMultipleChunks) { _gfs->setChunkSize(1); _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_EQUALS(gf.getNumChunks(), DATA_LEN); } TEST_F(GridFSTest, FindFile) { const char content_type[] = "text"; BSONObj result; result = _gfs->storeFile(DATA, DATA_LEN, DATA_NAME, content_type); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_TRUE(gf.exists()); ASSERT_TRUE(gf.getMetadata().isEmpty()); ASSERT_EQUALS(gf.getContentType(), content_type); ASSERT_EQUALS(gf.getFilename(), DATA_NAME); ASSERT_EQUALS(gf.getUploadDate(), result["uploadDate"].date()); ASSERT_EQUALS(gf.getChunkSize(), result["chunkSize"].numberInt()); ASSERT_EQUALS(gf.getMD5(), result["md5"].String()); ASSERT_EQUALS(gf.getContentLength(), UDATA_LEN); ASSERT_EQUALS(gf.getNumChunks(), 1); } TEST_F(GridFSTest, FindFileOrder) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); sleepmillis(100); // must sleep here to avoid identical uploadDate _gfs->storeFile(OTHER, OTHER_LEN, DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_EQUALS(gf.getContentLength(), UOTHER_LEN); GridFSChunk chunk = gf.getChunk(0); int data_length = chunk.len(); ASSERT_EQUALS(string(chunk.data(data_length), data_length), OTHER); } TEST_F(GridFSTest, WriteToFile) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); #if defined(_WIN32) char tmp_path[MAX_PATH - 14]; GetTempPathA(MAX_PATH, tmp_path); char tmp_name[MAX_PATH]; GetTempFileNameA(tmp_path, "tmp", 0U, tmp_name); #else char tmp_name[] = "/tmp/tmp.XXXXXXXX"; int tmp_fd = mkstemp(tmp_name); // We actually just need the filename and not the file descriptor // because the GridFS API takes a filename. So in order to silence // the compiler warning we use mkstemp instead of tmpnam but close // the fd we get as we dont actually care if creation is secure. if (tmp_fd == -1) std::abort(); else close(tmp_fd); #endif gf.write(tmp_name); ifstream written_file; written_file.open(tmp_name, ios::binary); stringstream written_data; written_data << written_file.rdbuf(); ASSERT_EQUALS(written_data.str(), DATA); written_file.close(); } TEST_F(GridFSTest, WriteToStream) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); stringstream ss; gf.write(ss); ASSERT_EQUALS(ss.str(), DATA); } TEST_F(GridFSTest, RemoveFile) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); _gfs->storeFile(OTHER, DATA_LEN, OTHER_NAME); GridFile gfd = _gfs->findFileByName(DATA_NAME); ASSERT_TRUE(gfd.exists()); GridFile gfo = _gfs->findFileByName(OTHER_NAME); ASSERT_TRUE(gfo.exists()); _gfs->removeFile(DATA_NAME); gfd = _gfs->findFileByName(DATA_NAME); ASSERT_FALSE(gfd.exists()); gfo = _gfs->findFileByName(OTHER_NAME); ASSERT_TRUE(gfo.exists()); } TEST_F(GridFSTest, ListFiles) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); _gfs->storeFile(DATA, DATA_LEN, OTHER_NAME); auto_ptr files = _gfs->list(); BSONObj file = files->peekFirst(); ASSERT_EQUALS(file["filename"].String(), DATA_NAME); ASSERT_EQUALS(files->itcount(), 2); ASSERT_EQUALS(files->getns(), "gridfs-test.fs.files"); } TEST_F(GridFSTest, ListFilesQuery) { _gfs->storeFile(DATA, DATA_LEN, DATA_NAME); auto_ptr files = _gfs->list(BSON("filename" << DATA_NAME)); ASSERT_EQUALS(files->itcount(), 1); auto_ptr files_bad = _gfs->list(BSON("filename" << OTHER_NAME)); ASSERT_EQUALS(files_bad->itcount(), 0); } TEST_F(GridFSTest, GridFileBuilder) { GridFileBuilder gfb(_gfs.get()); size_t totalSize = 0; for (int i = 0; i < DATA_LEN; i += 2) { size_t chunkSize = min(2, DATA_LEN - i); gfb.appendChunk(DATA + i, chunkSize); totalSize += chunkSize; } gfb.buildFile(DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_EQUALS(gf.getNumChunks(), 1); ASSERT_EQUALS(gf.getContentLength(), totalSize); } TEST_F(GridFSTest, GridFileBuilderMultipleChunks) { _gfs->setChunkSize(1); GridFileBuilder gfb(_gfs.get()); size_t total_size = 0; for (int i = 0; i < DATA_LEN; i += 2) { size_t chunk_size = min(2, DATA_LEN - i); gfb.appendChunk(DATA + i, chunk_size); total_size += chunk_size; } gfb.buildFile(DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_EQUALS(gf.getNumChunks(), DATA_LEN); ASSERT_EQUALS(gf.getContentLength(), total_size); } TEST_F(GridFSTest, GridFileBuilderAcrossChunkBoundry) { _gfs->setChunkSize(11); GridFileBuilder gfb(_gfs.get()); size_t total_size = 0; for (int i = 0; i < DATA_LEN; i += 2) { size_t chunk_size = min(2, DATA_LEN - i); gfb.appendChunk(DATA + i, chunk_size); total_size += chunk_size; } gfb.buildFile(DATA_NAME); GridFile gf = _gfs->findFileByName(DATA_NAME); ASSERT_EQUALS(gf.getContentLength(), total_size); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/integration/standalone/sasl_test.cpp000066400000000000000000000126731273231111400272570ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include "mongo/integration/integration_test.h" #include "mongo/util/mongoutils/str.h" #include "mongo/client/dbclient.h" using namespace mongo; namespace { bool supports_sasl(DBClientConnection& conn) { BSONObj result; conn.runCommand("admin", BSON("buildinfo" << true), result); return result["version"].toString() >= "2.5.3"; } TEST(SASLAuthentication, LDAP) { DBClientConnection conn; conn.connect("ldaptest.10gen.cc"); // only available internally or on jenkins if (supports_sasl(conn)) { conn.auth(BSON("mechanism" << "PLAIN" << "user" << "drivers-team" << "pwd" << "mongor0x$xgen" << "digestPassword" << false)); } else { // MongoDB version too old to support SASL SUCCEED(); } BSONObj result = conn.findOne("ldap.test", Query("{}")); ASSERT_TRUE(result["ldap"].trueValue()); ASSERT_EQUALS(result["authenticated"].str(), "yeah"); } TEST(SASLAuthentication, DISABLED_Kerberos) { // You must run kinit -p drivers@LDAPTEST.10GEN.CC before this test DBClientConnection conn; conn.connect("ldaptest.10gen.cc"); // only available internally or on jenkins if (supports_sasl(conn)) { conn.auth(BSON("mechanism" << "GSSAPI" << "user" << "drivers@LDAPTEST.10GEN.CC")); } else { // MongoDB version too old to support SASL SUCCEED(); } BSONObj result = conn.findOne("kerberos.test", Query("{}")); ASSERT_TRUE(result["kerberos"].trueValue()); ASSERT_EQUALS(result["authenticated"].str(), "yeah"); } TEST(SASLAuthentication, DISABLED_KerberosProperties) { // You must run kinit -p drivers@LDAPTEST.10GEN.CC before this test std::string connStr = str::stream() << "mongodb://drivers@ldaptest.10gen.cc/?" << "authMechanism=GSSAPI" << "&" << "authMechanismProperties=" << "SERVICE_NAME:mongodb" << "," << "SERVICE_REALM:LDAPTEST.10GEN.CC"; std::string errmsg; ConnectionString parsed(ConnectionString::parse(connStr, errmsg)); std::cout << errmsg << std::endl; boost::scoped_ptr conn; ASSERT_NO_THROW(conn.reset(dynamic_cast(parsed.connect(errmsg, 0)))); BSONObj result = conn->findOne("kerberos.test", Query("{}")); ASSERT_TRUE(result["kerberos"].trueValue()); ASSERT_EQUALS(result["authenticated"].str(), "yeah"); } TEST(SASLAuthentication, DISABLED_KerberosPropertiesInvalid) { // You must run kinit -p drivers@LDAPTEST.10GEN.CC before this test std::string connStr = str::stream() << "mongodb://drivers@ldaptest.10gen.cc/?" << "authMechanism=GSSAPI" << "&" << "authMechanismProperties=" << "SERVICE_NAME:mongodb" << "," << "SERVICE_REALM:LDAPTEST.10GEN.CC" << "," << "I_AM_NOT_VALID:meow"; std::string errmsg; ConnectionString parsed(ConnectionString::parse(connStr, errmsg)); std::cout << errmsg << std::endl; boost::scoped_ptr conn; ASSERT_THROW(conn.reset(dynamic_cast(parsed.connect(errmsg, 0))), UserException); } TEST(SASLAuthentication, DISABLED_KerberosPropertiesRedundant) { // You must run kinit -p drivers@LDAPTEST.10GEN.CC before this test std::string connStr = str::stream() << "mongodb://drivers@ldaptest.10gen.cc/?" << "gssapiServiceName=thisshouldnotwork" << "&" // can't set this and SERVICE_NAME << "authMechanism=GSSAPI" << "&" << "authMechanismProperties=" << "SERVICE_NAME:mongodb" << "," << "SERVICE_REALM:LDAPTEST.10GEN.CC"; std::string errmsg; ConnectionString parsed(ConnectionString::parse(connStr, errmsg)); std::cout << errmsg << std::endl; boost::scoped_ptr conn; ASSERT_THROW(conn.reset(dynamic_cast(parsed.connect(errmsg, 0))), UserException); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/000077500000000000000000000000001273231111400213455ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/appender.h000066400000000000000000000023071273231111400233160ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/status.h" namespace mongo { namespace logger { /** * Interface for sinks in a logging system. The core of logging is when events of type E are * appended to instances of Appender. * * Example concrete instances are ConsoleAppender, SyslogAppender and * RotatableFileAppender. */ template class Appender { public: typedef E Event; virtual ~Appender() {} /** * Appends "event", returns Status::OK() on success. */ virtual Status append(const Event& event) = 0; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/component_message_log_domain.cpp000066400000000000000000000053131273231111400277510ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/component_message_log_domain.h" namespace mongo { namespace logger { ComponentMessageLogDomain::ComponentMessageLogDomain() {} ComponentMessageLogDomain::~ComponentMessageLogDomain() {} bool ComponentMessageLogDomain::hasMinimumLogSeverity(LogComponent component) const { return _settings.hasMinimumLogSeverity(component); } bool ComponentMessageLogDomain::shouldLog(LogComponent component, LogSeverity severity) const { return _settings.shouldLog(component, severity); } bool ComponentMessageLogDomain::shouldLog(LogComponent component1, LogComponent component2, LogSeverity severity) const { return _settings.shouldLog(component1, severity) || _settings.shouldLog(component2, severity); } bool ComponentMessageLogDomain::shouldLog(LogComponent component1, LogComponent component2, LogComponent component3, LogSeverity severity) const { return _settings.shouldLog(component1, severity) || _settings.shouldLog(component2, severity) || _settings.shouldLog(component3, severity); } LogSeverity ComponentMessageLogDomain::getMinimumLogSeverity() const { return _settings.getMinimumLogSeverity(LogComponent::kDefault); } LogSeverity ComponentMessageLogDomain::getMinimumLogSeverity(LogComponent component) const { return _settings.getMinimumLogSeverity(component); } void ComponentMessageLogDomain::setMinimumLoggedSeverity(LogSeverity severity) { _settings.setMinimumLoggedSeverity(LogComponent::kDefault, severity); } void ComponentMessageLogDomain::setMinimumLoggedSeverity(LogComponent component, LogSeverity severity) { _settings.setMinimumLoggedSeverity(component, severity); } void ComponentMessageLogDomain::clearMinimumLoggedSeverity(LogComponent component) { _settings.clearMinimumLoggedSeverity(component); } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/component_message_log_domain.h000066400000000000000000000047661273231111400274310ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/logger/log_component_settings.h" #include "mongo/logger/message_log_domain.h" namespace mongo { namespace logger { /** * Logging domain for ephemeral messages with minimum severity. */ class MONGO_CLIENT_API ComponentMessageLogDomain : public MessageLogDomain { MONGO_DISALLOW_COPYING(ComponentMessageLogDomain); public: ComponentMessageLogDomain(); ~ComponentMessageLogDomain(); /** * Predicate that answers the questwion, "Should I, the caller, append to you, the log * domain, messages of the given severity?" True means yes. */ bool shouldLog(LogComponent component, LogSeverity severity) const; bool shouldLog(LogComponent component1, LogComponent component2, LogSeverity severity) const; bool shouldLog(LogComponent component1, LogComponent component2, LogComponent component3, LogSeverity severity) const; /** * Returns true if a minimum log severity has been set for this component. * Called by log level commands to query component severity configuration. */ bool hasMinimumLogSeverity(LogComponent component) const; /** * Gets the minimum severity of messages that should be sent to this LogDomain. */ LogSeverity getMinimumLogSeverity() const; LogSeverity getMinimumLogSeverity(LogComponent component) const; /** * Sets the minimum severity of messages that should be sent to this LogDomain. */ void setMinimumLoggedSeverity(LogSeverity severity); void setMinimumLoggedSeverity(LogComponent, LogSeverity severity); /** * Clears the minimum log severity for component. * For kDefault, severity level is initialized to default value. */ void clearMinimumLoggedSeverity(LogComponent component); private: LogComponentSettings _settings; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/encoder.h000066400000000000000000000020751273231111400231410ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include namespace mongo { namespace logger { /** * Interface for objects that encode Events to std::ostreams. * * Most appender implementations write to streams, and Encoders represent the process of * encoding events into streams. */ template class Encoder { public: virtual ~Encoder() {} virtual std::ostream& encode(const Event& event, std::ostream& os) = 0; }; } // namespace logger } // nnamspace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/labeled_level.h000066400000000000000000000047171273231111400243060ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/logger/log_severity.h" namespace mongo { namespace logger { /** * Deprecated utility for associating a string and log level together. */ class LabeledLevel { public: LabeledLevel(int level) : _level(level) {} LabeledLevel(const char* label, int level) : _label(label), _level(level) {} LabeledLevel(const std::string& label, int level) : _label(label), _level(level) {} LabeledLevel operator+(int i) const { return LabeledLevel(_label, _level + i); } LabeledLevel operator-(int i) const { return LabeledLevel(_label, _level - i); } const std::string& getLabel() const { return _label; } int getLevel() const { return _level; } operator LogSeverity() const { return logger::LogSeverity::cast(_level); } private: std::string _label; int _level; }; inline bool operator<(const LabeledLevel& ll, const int i) { return ll.getLevel() < i; } inline bool operator<(const int i, const LabeledLevel& ll) { return i < ll.getLevel(); } inline bool operator>(const LabeledLevel& ll, const int i) { return ll.getLevel() > i; } inline bool operator>(const int i, const LabeledLevel& ll) { return i > ll.getLevel(); } inline bool operator<=(const LabeledLevel& ll, const int i) { return ll.getLevel() <= i; } inline bool operator<=(const int i, const LabeledLevel& ll) { return i <= ll.getLevel(); } inline bool operator>=(const LabeledLevel& ll, const int i) { return ll.getLevel() >= i; } inline bool operator>=(const int i, const LabeledLevel& ll) { return i >= ll.getLevel(); } inline bool operator==(const LabeledLevel& ll, const int i) { return ll.getLevel() == i; } inline bool operator==(const int i, const LabeledLevel& ll) { return i == ll.getLevel(); } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_component.cpp000066400000000000000000000135011273231111400247140ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/log_component.h" #include #include "mongo/base/init.h" #include "mongo/util/assert_util.h" namespace mongo { namespace logger { namespace { // Component dotted names. // Lazily evaluated in LogComponent::getDottedName(). std::string _dottedNames[LogComponent::kNumLogComponents + 1]; /** * Returns StringData created from a string literal */ template StringData createStringData(const char(&val)[N]) { return StringData(val, StringData::LiteralTag()); } // // Fully initialize _dottedNames before we enter multithreaded execution. // MONGO_INITIALIZER_WITH_PREREQUISITES(SetupDottedNames, MONGO_NO_PREREQUISITES)(InitializerContext* context) { for (int i = 0; i <= int(LogComponent::kNumLogComponents); ++i) { logger::LogComponent component = static_cast(i); component.getDottedName(); } return Status::OK(); } } // namespace // Children always come after parent component. // This makes it unnecessary to compute children of each component // when setting/clearing log severities in LogComponentSettings. #define DECLARE_LOG_COMPONENT_PARENT(CHILD, PARENT) \ case (CHILD): \ do { \ BOOST_STATIC_ASSERT(int(CHILD) > int(PARENT)); \ return (PARENT); \ } while (0) LogComponent LogComponent::parent() const { switch (_value) { case kDefault: return kNumLogComponents; DECLARE_LOG_COMPONENT_PARENT(kJournal, kStorage); case kNumLogComponents: return kNumLogComponents; default: return kDefault; } invariant(false); } StringData LogComponent::toStringData() const { switch (_value) { case kDefault: return createStringData("default"); case kAccessControl: return createStringData("accessControl"); case kCommand: return createStringData("command"); case kControl: return createStringData("control"); case kGeo: return createStringData("geo"); case kIndex: return createStringData("index"); case kNetwork: return createStringData("network"); case kQuery: return createStringData("query"); case kReplication: return createStringData("replication"); case kSharding: return createStringData("sharding"); case kStorage: return createStringData("storage"); case kJournal: return createStringData("journal"); case kWrite: return createStringData("write"); case kNumLogComponents: return createStringData("total"); // No default. Compiler should complain if there's a log component that's not handled. } invariant(false); } std::string LogComponent::getShortName() const { return toStringData().toString(); } std::string LogComponent::getDottedName() const { // Lazily evaluate dotted names in anonymous namespace. if (_dottedNames[_value].empty()) { switch (_value) { case kDefault: _dottedNames[_value] = getShortName(); break; case kNumLogComponents: _dottedNames[_value] = getShortName(); break; default: // Omit short name of 'default' component from dotted name. if (parent() == kDefault) { _dottedNames[_value] = getShortName(); } else { _dottedNames[_value] = parent().getDottedName() + "." + getShortName(); } break; } } return _dottedNames[_value]; } StringData LogComponent::getNameForLog() const { switch (_value) { case kDefault: return createStringData("- "); case kAccessControl: return createStringData("ACCESS "); case kCommand: return createStringData("COMMAND "); case kControl: return createStringData("CONTROL "); case kGeo: return createStringData("GEO "); case kIndex: return createStringData("INDEX "); case kNetwork: return createStringData("NETWORK "); case kQuery: return createStringData("QUERY "); case kReplication: return createStringData("REPL "); case kSharding: return createStringData("SHARDING"); case kStorage: return createStringData("STORAGE "); case kJournal: return createStringData("JOURNAL "); case kWrite: return createStringData("WRITE "); case kNumLogComponents: return createStringData("TOTAL "); // No default. Compiler should complain if there's a log component that's not handled. } invariant(false); } std::ostream& operator<<(std::ostream& os, LogComponent component) { return os << component.getNameForLog(); } } // logger } // mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_component.h000066400000000000000000000047511273231111400243700ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" namespace mongo { namespace logger { /** * Log components. * Debug messages logged using the LOG() or MONGO_LOG_COMPONENT(). * Macros may be associated with one or more log components. */ class MONGO_CLIENT_API LogComponent { public: enum Value { kDefault = 0, kAccessControl, kCommand, kControl, kGeo, kIndex, kNetwork, kQuery, kReplication, kSharding, kStorage, kJournal, kWrite, kNumLogComponents }; /* implicit */ LogComponent(Value value) : _value(value) {} operator Value() const { return _value; } /** * Returns parent component. * Returns kNumComponents if parent component is not defined (for kDefault or * kNumLogComponents). */ LogComponent parent() const; /** * Returns short name as a StringData. */ StringData toStringData() const; /** * Returns short name of log component. * Used to generate server parameter names in the format "logLevel_". */ std::string getShortName() const; /** * Returns dotted name of log component - short name prefixed by dot-separated names of * ancestors. * Used to generate command line and config file option names. */ std::string getDottedName() const; /** * Returns name suitable for inclusion in formatted log message. * This is derived from upper-casing the short name with some padding to * fit into a fixed length field. */ StringData getNameForLog() const; private: Value _value; }; MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& os, LogComponent component); } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_component_settings.cpp000066400000000000000000000072721273231111400266440ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/log_component_settings.h" #include "mongo/util/assert_util.h" #include "mongo/util/debug_util.h" namespace mongo { namespace logger { LogComponentSettings::LogComponentSettings() { _minimumLoggedSeverity[LogComponent::kDefault] = char(LogSeverity::Log().toInt()); for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { _minimumLoggedSeverity[i] = _minimumLoggedSeverity[LogComponent::kDefault]; _hasMinimumLoggedSeverity[i] = false; } _hasMinimumLoggedSeverity[LogComponent::kDefault] = true; } LogComponentSettings::~LogComponentSettings() {} bool LogComponentSettings::hasMinimumLogSeverity(LogComponent component) const { dassert(int(component) >= 0 && int(component) < LogComponent::kNumLogComponents); return _hasMinimumLoggedSeverity[component]; } LogSeverity LogComponentSettings::getMinimumLogSeverity(LogComponent component) const { dassert(int(component) >= 0 && int(component) < LogComponent::kNumLogComponents); return LogSeverity::cast(_minimumLoggedSeverity[component]); } void LogComponentSettings::setMinimumLoggedSeverity(LogComponent component, LogSeverity severity) { dassert(int(component) >= 0 && int(component) < LogComponent::kNumLogComponents); _minimumLoggedSeverity[component] = char(severity.toInt()); _hasMinimumLoggedSeverity[component] = true; // Every unconfigured component will inherit log severity from parent. // Traversing the severity array once works because child components always // come after the parent in the LogComponent::Value enumeration. for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { if (!_hasMinimumLoggedSeverity[i]) { LogComponent::Value v = LogComponent::Value(i); LogComponent parentComponent = LogComponent(v).parent(); LogSeverity parentSeverity = getMinimumLogSeverity(parentComponent); _minimumLoggedSeverity[i] = char(parentSeverity.toInt()); } } } void LogComponentSettings::clearMinimumLoggedSeverity(LogComponent component) { dassert(int(component) >= 0 && int(component) < LogComponent::kNumLogComponents); // LogComponent::kDefault must always be configured. if (component == LogComponent::kDefault) { setMinimumLoggedSeverity(component, LogSeverity::Log()); return; } // Set unconfigured severity level to match LogComponent::kDefault. setMinimumLoggedSeverity(component, getMinimumLogSeverity(component.parent())); _hasMinimumLoggedSeverity[component] = false; } bool LogComponentSettings::shouldLog(LogComponent component, LogSeverity severity) const { dassert(int(component) >= 0 && int(component) < LogComponent::kNumLogComponents); // Should match parent component if minimum severity level is not configured for // component. dassert(_hasMinimumLoggedSeverity[component] || _minimumLoggedSeverity[component] == _minimumLoggedSeverity[component.parent()]); return severity >= LogSeverity::cast(_minimumLoggedSeverity[component]); } } // logger } // mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_component_settings.h000066400000000000000000000060151273231111400263030ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/disallow_copying.h" #include "mongo/logger/log_component.h" #include "mongo/logger/log_severity.h" namespace mongo { namespace logger { /** * Contains log severities for a list of log components. * kDefault always has a log severity defined but it is not necessary to * provide log severities for the other components (up to but not including kNumLogComponents). */ class LogComponentSettings { MONGO_DISALLOW_COPYING(LogComponentSettings); public: LogComponentSettings(); ~LogComponentSettings(); /** * Returns true if a minimum log severity has been set for this component. * Used by log level commands to query component severity configuration. */ bool hasMinimumLogSeverity(LogComponent component) const; /** * Gets the minimum log severity for component. * Result is defined only if hasMinimumLogSeverity() returns true for component. */ LogSeverity getMinimumLogSeverity(LogComponent component) const; /** * Sets the minimum log severity for component. */ void setMinimumLoggedSeverity(LogComponent component, LogSeverity severity); /** * Clears the minimum log severity for component. * For kDefault, severity level is initialized to default value. */ void clearMinimumLoggedSeverity(LogComponent component); /** * Predicate that answers the question, "Should I, the caller, append to you, the log * domain, componented messages of the given severity?" True means yes. * * If minimum severity levels are not configured, compare 'severity' against the configured * level for kDefault. */ bool shouldLog(LogComponent component, LogSeverity severity) const; private: // True if a log severity is explicitly set for a component. // This differentiates between unconfigured components and components that happen to have // the same severity as kDefault. // This is also used to update the severities of unconfigured components when the severity // for kDefault is modified. bool _hasMinimumLoggedSeverity[LogComponent::kNumLogComponents]; // Log severities for components. // Store numerical values of severities to be cache-line friendly. // Set to kDefault minimum logged severity if _hasMinimumLoggedSeverity[i] is false. char _minimumLoggedSeverity[LogComponent::kNumLogComponents]; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_domain-impl.h000066400000000000000000000051721273231111400245720ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/status.h" #include "mongo/logger/message_log_domain.h" /* * Implementation of LogDomain. Include this in cpp files to instantiate new LogDomain types. * See message_log_domain.h, e.g. */ namespace mongo { namespace logger { template LogDomain::LogDomain() : _abortOnFailure(false) {} template LogDomain::~LogDomain() { clearAppenders(); } template Status LogDomain::append(const E& event) { for (typename AppenderVector::const_iterator iter = _appenders.begin(); iter != _appenders.end(); ++iter) { if (*iter) { Status status = (*iter)->append(event); if (!status.isOK()) { if (_abortOnFailure) { ::abort(); } return status; } } } return Status::OK(); } template typename LogDomain::AppenderHandle LogDomain::attachAppender( typename LogDomain::AppenderAutoPtr appender) { typename AppenderVector::iterator iter = std::find(_appenders.begin(), _appenders.end(), static_cast(NULL)); if (iter == _appenders.end()) { _appenders.push_back(appender.release()); return AppenderHandle(_appenders.size() - 1); } else { *iter = appender.release(); return AppenderHandle(iter - _appenders.begin()); } } template typename LogDomain::AppenderAutoPtr LogDomain::detachAppender( typename LogDomain::AppenderHandle handle) { EventAppender*& appender = _appenders.at(handle._index); AppenderAutoPtr result(appender); appender = NULL; return result; } template void LogDomain::clearAppenders() { for (typename AppenderVector::const_iterator iter = _appenders.begin(); iter != _appenders.end(); ++iter) { delete *iter; } _appenders.clear(); } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_domain.h000066400000000000000000000101771273231111400236340ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/base/disallow_copying.h" #include "mongo/logger/appender.h" #include "mongo/logger/log_severity.h" namespace mongo { namespace logger { /** * Logging domain for events of type E. * * A logging domain consists of a set of Appenders. * * TODO: The severity doesn't seem to apply for auditing, maybe it only belongs on the * MessageLogManager? We don't really have multiple tunable logging domains, right now. Other * than the global domain, shouldLog doesn't matter. * * Usage: Configure the log domain in a single threaded context, using attachAppender, * detachAppender and clearAppenders(). The domain takes ownership of any attached appender, * returning an AppenderHandle for each attached appender. That handle may be used later to * detach the appender, causing the domain to release ownership of it. Mostly, this * attach/detach behavior is useful in testing, since you do not want to change the appenders of * a domain that is currently receiving append() calls. * * Once you've configured the domain, call append() from potentially many threads, to add log * messages. */ template class MONGO_CLIENT_API LogDomain { MONGO_DISALLOW_COPYING(LogDomain); public: typedef E Event; typedef Appender EventAppender; /** * Opaque handle returned by attachAppender(), which can be subsequently passed to * detachAppender() to detach an appender from an instance of LogDomain. */ class AppenderHandle { friend class LogDomain; public: AppenderHandle() {} private: explicit AppenderHandle(size_t index) : _index(index) {} size_t _index; }; // TODO(schwerin): Replace with unique_ptr in C++11. typedef std::auto_ptr AppenderAutoPtr; LogDomain(); ~LogDomain(); /** * Receives an event for logging, calling append(event) on all attached appenders. * * If any appender fails, the behavior is determined by the abortOnFailure flag: * *If abortOnFailure is set, ::abort() is immediately called. * *If abortOnFailure is not set, the error is returned and no further appenders are called. */ Status append(const Event& event); /** * Gets the state of the abortOnFailure flag. */ bool getAbortOnFailure() const { return _abortOnFailure; } /** * Sets the state of the abortOnFailure flag. */ void setAbortOnFailure(bool abortOnFailure) { _abortOnFailure = abortOnFailure; } // // Configuration methods. Must be synchronized with each other and calls to "append" by the // caller. // /** * Attaches "appender" to this domain, taking ownership of it. Returns a handle that may be * used later to detach this appender. */ AppenderHandle attachAppender(AppenderAutoPtr appender); /** * Detaches the appender referenced by "handle" from this domain, releasing ownership of it. * Returns an auto_ptr to the handler to the caller, who is now responsible for its * deletion. Caller should consider "handle" is invalid after this call. */ AppenderAutoPtr detachAppender(AppenderHandle handle); /** * Destroy all attached appenders, invalidating all handles. */ void clearAppenders(); private: typedef std::vector AppenderVector; AppenderVector _appenders; bool _abortOnFailure; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_function_test.cpp000066400000000000000000000107451273231111400256050ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kReplication #include "mongo/platform/basic.h" #include "mongo/logger/log_test.h" #include #include #include #include "mongo/logger/appender.h" #include "mongo/logger/encoder.h" #include "mongo/logger/log_component.h" #include "mongo/logger/message_event_utf8_encoder.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" using namespace mongo::logger; namespace mongo { namespace { typedef LogTest LogTestDetailsEncoder; // Constants for log component test cases. const LogComponent componentA = LogComponent::kCommand; const LogComponent componentB = MONGO_LOG_DEFAULT_COMPONENT; // Tests pass through of log component: // unconditional log functions -> LogStreamBuilder -> MessageEventEphemeral // -> MessageEventDetailsEncoder // MONGO_DEFAULT_LOG_COMPONENT is set to kReplication before including util/log.h // so non-debug logging without explicit component will log with kReplication instead // of kDefault. TEST_F(LogTestDetailsEncoder, LogFunctionsOverrideGlobalComponent) { // severe() - no component specified. severe() << "This is logged"; ASSERT_TRUE(shouldLog(LogSeverity::Severe())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentB.getNameForLog()), std::string::npos); // severe() - with component. _logLines.clear(); severe(componentA) << "This is logged"; ASSERT_TRUE(logger::globalLogDomain()->shouldLog(componentA, LogSeverity::Severe())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentA.getNameForLog()), std::string::npos); // error() - no component specified. _logLines.clear(); error() << "This is logged"; ASSERT_TRUE(shouldLog(LogSeverity::Error())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentB.getNameForLog()), std::string::npos); // error() - with component. _logLines.clear(); error(componentA) << "This is logged"; ASSERT_TRUE(logger::globalLogDomain()->shouldLog(componentA, LogSeverity::Error())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentA.getNameForLog()), std::string::npos); // warning() - no component specified. _logLines.clear(); warning() << "This is logged"; ASSERT_TRUE(shouldLog(LogSeverity::Warning())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentB.getNameForLog()), std::string::npos); // warning() - with component. _logLines.clear(); warning(componentA) << "This is logged"; ASSERT_TRUE(logger::globalLogDomain()->shouldLog(componentA, LogSeverity::Warning())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentA.getNameForLog()), std::string::npos); // log() - no component specified. _logLines.clear(); log() << "This is logged"; ASSERT_TRUE(shouldLog(LogSeverity::Log())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentB.getNameForLog()), std::string::npos); // log() - with component. _logLines.clear(); log(componentA) << "This is logged"; ASSERT_TRUE(logger::globalLogDomain()->shouldLog(componentA, LogSeverity::Log())); ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentA.getNameForLog()), std::string::npos); } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_manager.cpp000066400000000000000000000021771273231111400243330ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/log_manager.h" namespace mongo { namespace logger { LogManager::LogManager() {} LogManager::~LogManager() { for (DomainsByNameMap::iterator iter = _domains.begin(); iter != _domains.end(); ++iter) { delete iter->second; } } MessageLogDomain* LogManager::getNamedDomain(const std::string& name) { MessageLogDomain*& domain = _domains[name]; if (!domain) { domain = new MessageLogDomain; } return domain; } } // logger } // mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_manager.h000066400000000000000000000030671273231111400237770ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" #include "mongo/logger/component_message_log_domain.h" #include "mongo/platform/unordered_map.h" namespace mongo { namespace logger { /** * Container for managing log domains. * * Use this while setting up the logging system, before launching any threads. */ class LogManager { MONGO_DISALLOW_COPYING(LogManager); public: LogManager(); ~LogManager(); /** * Gets the global domain for this manager. It has no name. */ ComponentMessageLogDomain* getGlobalDomain() { return &_globalDomain; } /** * Get the log domain with the given name, creating if needed. */ MessageLogDomain* getNamedDomain(const std::string& name); private: typedef unordered_map DomainsByNameMap; DomainsByNameMap _domains; ComponentMessageLogDomain _globalDomain; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_severity-inl.h000066400000000000000000000037451273231111400250220ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { namespace logger { LogSeverity LogSeverity::Severe() { return LogSeverity(-4); } LogSeverity LogSeverity::Error() { return LogSeverity(-3); } LogSeverity LogSeverity::Warning() { return LogSeverity(-2); } LogSeverity LogSeverity::Info() { return LogSeverity(-1); } LogSeverity LogSeverity::Log() { return LogSeverity(0); } LogSeverity LogSeverity::Debug(int debugLevel) { return LogSeverity(debugLevel); } LogSeverity LogSeverity::cast(int ll) { return LogSeverity(ll); } int LogSeverity::toInt() const { return _severity; } LogSeverity LogSeverity::moreSevere() const { return LogSeverity(_severity - 1); } LogSeverity LogSeverity::lessSevere() const { return LogSeverity(_severity + 1); } bool LogSeverity::operator==(LogSeverity other) const { return _severity == other._severity; } bool LogSeverity::operator!=(LogSeverity other) const { return _severity != other._severity; } bool LogSeverity::operator<(LogSeverity other) const { return _severity > other._severity; } bool LogSeverity::operator<=(LogSeverity other) const { return _severity >= other._severity; } bool LogSeverity::operator>(LogSeverity other) const { return _severity < other._severity; } bool LogSeverity::operator>=(LogSeverity other) const { return _severity <= other._severity; } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_severity.cpp000066400000000000000000000050301273231111400245620ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/log_severity.h" #include namespace mongo { namespace logger { namespace { const char unknownSeverityString[] = "UNKNOWN"; const char severeSeverityString[] = "SEVERE"; const char errorSeverityString[] = "ERROR"; const char warningSeverityString[] = "warning"; const char infoSeverityString[] = "info"; const char debugSeverityString[] = "debug"; } // namespace StringData LogSeverity::toStringData() const { if (_severity > 0) return StringData(debugSeverityString, StringData::LiteralTag()); if (*this == LogSeverity::Severe()) return StringData(severeSeverityString, StringData::LiteralTag()); if (*this == LogSeverity::Error()) return StringData(errorSeverityString, StringData::LiteralTag()); if (*this == LogSeverity::Warning()) return StringData(warningSeverityString, StringData::LiteralTag()); if (*this == LogSeverity::Info()) return StringData(infoSeverityString, StringData::LiteralTag()); if (*this == LogSeverity::Log()) return StringData(infoSeverityString, StringData::LiteralTag()); return StringData(unknownSeverityString, StringData::LiteralTag()); } char LogSeverity::toChar() const { if (_severity > 0) return 'D'; // 'S' might be confused with "Success" // Return 'F' to imply Fatal instead. if (*this == LogSeverity::Severe()) return 'F'; if (*this == LogSeverity::Error()) return 'E'; if (*this == LogSeverity::Warning()) return 'W'; if (*this == LogSeverity::Info()) return 'I'; if (*this == LogSeverity::Log()) return 'I'; // Should not reach here - returning 'U' for Unknown severity // to be consistent with toStringData(). return 'U'; } std::ostream& operator<<(std::ostream& os, LogSeverity severity) { return os << severity.toStringData(); } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_severity.h000066400000000000000000000103601273231111400242310ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/string_data.h" #include "mongo/client/export_macros.h" namespace mongo { namespace logger { /** * Representation of the severity / priority of a log message. * * Severities are totally ordered, from most severe to least severe as follows: * Severe, Error, Warning, Info, Log, Debug(1), Debug(2), ... */ class MONGO_CLIENT_API LogSeverity { public: // // Static factory methods for getting LogSeverity objects of the various severity levels. // static inline LogSeverity Severe(); static inline LogSeverity Error(); static inline LogSeverity Warning(); static inline LogSeverity Info(); static inline LogSeverity Log(); // === Debug(0) static inline LogSeverity Debug(int debugLevel); /** * Casts an integer to a severity. * * Do not use this. It exists to enable a handful of leftover uses of LOG(0) and the * deprecated LabeledLevel. */ static inline LogSeverity cast(int); inline int toInt() const; /** * Returns a LogSeverity object that is one unit "more severe" than this one. */ inline LogSeverity moreSevere() const; /** * Returns a LogSeverity object that is one unit "less severe" than this one. */ inline LogSeverity lessSevere() const; /** * Returns a string naming this severity level. * * See toStringData(), below. */ inline std::string toString() const; /** * Returns a StringData naming this security level. * * Not all levels are uniquely named. Debug(N) is named "debug", regardless of "N", * e.g. */ StringData toStringData() const; /** * Returns a single capital letter naming this severity level. * Equivalent to upper-case of first letter of toStringData() result. * * Not all levels are uniquely named. */ char toChar() const; // // Comparison operations. // /// Returns true if this is exactly as severe as other. inline bool operator==(const LogSeverity other) const; /// Returns true if this is not exactly as severe as other. inline bool operator!=(const LogSeverity other) const; /// Returns true if this is less severe than other. inline bool operator<(const LogSeverity other) const; /// Returns true if this is no more severe than other. inline bool operator<=(const LogSeverity other) const; /// Returns true if this is more severe than other. inline bool operator>(const LogSeverity other) const; /// Returns true if this is no less severe than other. inline bool operator>=(const LogSeverity other) const; private: explicit LogSeverity(int severity) : _severity(severity) {} /// The stored severity. More negative is more severe. NOTE: This means that the >, <, >= /// and <= operators on LogSeverity have opposite sense of the same operators on the /// underlying integer. That is, given severities S1 and S2, S1 > S2 means that S1.toInt() /// < S2.toInt(). /// /// TODO(schwerin): Decide if we should change this so more positive is more severe. The /// logLevel parameter in the database is more compatible with this sense, but it's not /// totally intuitive. One could also remove the operator overloads in favor of named /// methods, isNoMoreSevereThan, isLessSevereThan, isMoreSevereThan, isNoLessSevereThan, /// isSameSeverity and isDifferentSeverity. int _severity; }; MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& os, LogSeverity severity); } // namespace logger } // namespace mongo #include "mongo/logger/log_severity-inl.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_test.cpp000066400000000000000000000533271273231111400237030ustar00rootroot00000000000000 /* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/platform/basic.h" #include "mongo/logger/log_test.h" #include #include #include #include "mongo/logger/appender.h" #include "mongo/logger/encoder.h" #include "mongo/logger/log_component.h" #include "mongo/logger/log_component_settings.h" #include "mongo/logger/message_event_utf8_encoder.h" #include "mongo/logger/message_log_domain.h" #include "mongo/platform/compiler.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" using namespace mongo::logger; namespace mongo { namespace { typedef LogTest LogTestDetailsEncoder; typedef LogTest LogTestUnadornedEncoder; TEST_F(LogTestUnadornedEncoder, logContext) { logContext("WHA!"); ASSERT_EQUALS(_logLines.size(), 1U); ASSERT_NOT_EQUALS(_logLines[0].find("WHA!"), std::string::npos); // TODO(schwerin): Ensure that logContext rights a proper context to the log stream, // including the address of the logContext() function. // void const* logContextFn = reinterpret_cast(logContext); } class CountAppender : public Appender { public: CountAppender() : _count(0) {} virtual ~CountAppender() {} virtual Status append(const MessageEventEphemeral& event) { ++_count; return Status::OK(); } int getCount() { return _count; } private: int _count; }; /** Simple tests for detaching appenders. */ TEST_F(LogTestUnadornedEncoder, DetachAppender) { MessageLogDomain::AppenderAutoPtr countAppender(new CountAppender); MessageLogDomain domain; // Appending to the domain before attaching the appender does not affect the appender. domain.append(MessageEventEphemeral(0ULL, LogSeverity::Log(), "", "1")); ASSERT_EQUALS(0, dynamic_cast(countAppender.get())->getCount()); // Appending to the domain after attaching the appender does affect the appender. MessageLogDomain::AppenderHandle handle = domain.attachAppender(countAppender); domain.append(MessageEventEphemeral(0ULL, LogSeverity::Log(), "", "2")); countAppender = domain.detachAppender(handle); ASSERT_EQUALS(1, dynamic_cast(countAppender.get())->getCount()); // Appending to the domain after detaching the appender does not affect the appender. domain.append(MessageEventEphemeral(0ULL, LogSeverity::Log(), "", "3")); ASSERT_EQUALS(1, dynamic_cast(countAppender.get())->getCount()); } class A { public: std::string toString() const { log() << "Golly!\n"; return "Golly!"; } }; // Tests that logging while in the midst of logging produces two distinct log messages, with the // inner log message appearing before the outer. TEST_F(LogTestUnadornedEncoder, LogstreamBuilderReentrance) { log() << "Logging A() -- " << A() << " -- done!" << std::endl; ASSERT_EQUALS(2U, _logLines.size()); ASSERT_EQUALS(std::string("Golly!\n"), _logLines[0]); ASSERT_EQUALS(std::string("Logging A() -- Golly! -- done!\n"), _logLines[1]); } // // Instantiating this object is a basic test of static-initializer-time logging. // class B { public: B() { log() << "Exercising initializer time logging."; } } b; // Constants for log component test cases. const LogComponent componentDefault = LogComponent::kDefault; const LogComponent componentA = LogComponent::kCommand; const LogComponent componentB = LogComponent::kAccessControl; const LogComponent componentC = LogComponent::kNetwork; const LogComponent componentD = LogComponent::kStorage; const LogComponent componentE = LogComponent::kJournal; // No log component declared at file scope. // Component severity configuration: // LogComponent::kDefault: 2 TEST_F(LogTestUnadornedEncoder, MongoLogMacroNoFileScopeLogComponent) { globalLogDomain()->setMinimumLoggedSeverity(LogSeverity::Debug(2)); LOG(2) << "This is logged"; LOG(3) << "This is not logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]); // MONGO_LOG_COMPONENT _logLines.clear(); MONGO_LOG_COMPONENT(2, componentA) << "This is logged"; MONGO_LOG_COMPONENT(3, componentA) << "This is not logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]); // MONGO_LOG_COMPONENT2 _logLines.clear(); MONGO_LOG_COMPONENT2(2, componentA, componentB) << "This is logged"; MONGO_LOG_COMPONENT2(3, componentA, componentB) << "This is not logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]); // MONGO_LOG_COMPONENT3 _logLines.clear(); MONGO_LOG_COMPONENT3(2, componentA, componentB, componentC) << "This is logged"; MONGO_LOG_COMPONENT3(3, componentA, componentB, componentC) << "This is not logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]); } // // Component log level tests. // The global log manager holds the component log level configuration for the global log domain. // LOG() and MONGO_LOG_COMPONENT() macros in util/log.h determine at runtime if a log message // should be written to the log domain. // TEST_F(LogTestUnadornedEncoder, LogComponentSettingsMinimumLogSeverity) { LogComponentSettings settings; ASSERT_TRUE(settings.hasMinimumLogSeverity(LogComponent::kDefault)); ASSERT_TRUE(settings.getMinimumLogSeverity(LogComponent::kDefault) == LogSeverity::Log()); for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { LogComponent component = static_cast(i); if (component == LogComponent::kDefault) { continue; } ASSERT_FALSE(settings.hasMinimumLogSeverity(component)); } // Override and clear minimum severity level. for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { LogComponent component = static_cast(i); LogSeverity severity = LogSeverity::Debug(2); // Override severity level. settings.setMinimumLoggedSeverity(component, severity); ASSERT_TRUE(settings.hasMinimumLogSeverity(component)); ASSERT_TRUE(settings.getMinimumLogSeverity(component) == severity); // Clear severity level. // Special case: when clearing LogComponent::kDefault, the corresponding // severity level is set to default values (ie. Log()). settings.clearMinimumLoggedSeverity(component); if (component == LogComponent::kDefault) { ASSERT_TRUE(settings.hasMinimumLogSeverity(component)); ASSERT_TRUE(settings.getMinimumLogSeverity(LogComponent::kDefault) == LogSeverity::Log()); } else { ASSERT_FALSE(settings.hasMinimumLogSeverity(component)); } } } // Test for shouldLog() when the minimum logged severity is set only for LogComponent::kDefault. TEST_F(LogTestUnadornedEncoder, LogComponentSettingsShouldLogDefaultLogComponentOnly) { LogComponentSettings settings; // Initial log severity for LogComponent::kDefault is Log(). ASSERT_TRUE(shouldLog(LogSeverity::Info())); ASSERT_TRUE(shouldLog(LogSeverity::Log())); ASSERT_FALSE(shouldLog(LogSeverity::Debug(1))); ASSERT_FALSE(shouldLog(LogSeverity::Debug(2))); // If any components are provided to shouldLog(), we should get the same outcome // because we have not configured any non-LogComponent::kDefault components. ASSERT_TRUE(settings.shouldLog(componentA, LogSeverity::Log())); ASSERT_FALSE(settings.shouldLog(componentA, LogSeverity::Debug(1))); // Set minimum logged severity so that Debug(1) messages are written to log domain. settings.setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); ASSERT_TRUE(shouldLog(LogSeverity::Info())); ASSERT_TRUE(shouldLog(LogSeverity::Log())); ASSERT_TRUE(shouldLog(LogSeverity::Debug(1))); ASSERT_FALSE(shouldLog(LogSeverity::Debug(2))); // Revert back. logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Log()); // Same results when components are supplied to shouldLog(). ASSERT_TRUE(settings.shouldLog(componentA, LogSeverity::Debug(1))); ASSERT_FALSE(settings.shouldLog(componentA, LogSeverity::Debug(2))); } // Test for shouldLog() when we have configured a single component. // Also checks that severity level has been reverted to match LogComponent::kDefault // after clearing level. // Minimum severity levels: // LogComponent::kDefault: 1 // componentA: 2 TEST_F(LogTestUnadornedEncoder, LogComponentSettingsShouldLogSingleComponent) { LogComponentSettings settings; settings.setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); settings.setMinimumLoggedSeverity(componentA, LogSeverity::Debug(2)); // Components for log message: componentA only. ASSERT_TRUE(settings.shouldLog(componentA, LogSeverity::Debug(2))); ASSERT_FALSE(settings.shouldLog(componentA, LogSeverity::Debug(3))); // Clear severity level for componentA and check shouldLog() again. settings.clearMinimumLoggedSeverity(componentA); ASSERT_TRUE(settings.shouldLog(componentA, LogSeverity::Debug(1))); ASSERT_FALSE(settings.shouldLog(componentA, LogSeverity::Debug(2))); // Test shouldLog() with global settings. logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); // Components for log message: LogComponent::kDefault only. ASSERT_TRUE(shouldLog(LogSeverity::Debug(1))); ASSERT_FALSE(shouldLog(LogSeverity::Debug(2))); logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Log()); } // Test for shouldLog() when we have configured multiple components. // Minimum severity levels: // LogComponent::kDefault: 1 // componentA: 2 // componentB: 0 TEST_F(LogTestUnadornedEncoder, LogComponentSettingsShouldLogMultipleComponentsConfigured) { LogComponentSettings settings; settings.setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); settings.setMinimumLoggedSeverity(componentA, LogSeverity::Debug(2)); settings.setMinimumLoggedSeverity(componentB, LogSeverity::Log()); // Components for log message: componentA only. ASSERT_TRUE(settings.shouldLog(componentA, LogSeverity::Debug(2))); ASSERT_FALSE(settings.shouldLog(componentA, LogSeverity::Debug(3))); // Components for log message: componentB only. ASSERT_TRUE(settings.shouldLog(componentB, LogSeverity::Log())); ASSERT_FALSE(settings.shouldLog(componentB, LogSeverity::Debug(1))); // Components for log message: componentC only. // Since a component-specific minimum severity is not configured for componentC, // shouldLog() falls back on LogComponent::kDefault. ASSERT_TRUE(settings.shouldLog(componentC, LogSeverity::Debug(1))); ASSERT_FALSE(settings.shouldLog(componentC, LogSeverity::Debug(2))); // Test shouldLog() with global settings. logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); // Components for log message: LogComponent::kDefault only. ASSERT_TRUE(shouldLog(LogSeverity::Debug(1))); ASSERT_FALSE(shouldLog(LogSeverity::Debug(2))); logger::globalLogDomain()->setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Log()); } // Log component hierarchy. TEST_F(LogTestUnadornedEncoder, LogComponentHierarchy) { // Parent component is not meaningful for kDefault and kNumLogComponents. ASSERT_EQUALS(LogComponent::kNumLogComponents, LogComponent(LogComponent::kDefault).parent()); ASSERT_EQUALS(LogComponent::kNumLogComponents, LogComponent(LogComponent::kNumLogComponents).parent()); // Default -> ComponentD -> ComponentE ASSERT_EQUALS(LogComponent::kDefault, LogComponent(componentD).parent()); ASSERT_EQUALS(componentD, LogComponent(componentE).parent()); ASSERT_NOT_EQUALS(LogComponent::kDefault, LogComponent(componentE).parent()); // Log components should inherit parent's log severity in settings. LogComponentSettings settings; settings.setMinimumLoggedSeverity(LogComponent::kDefault, LogSeverity::Debug(1)); settings.setMinimumLoggedSeverity(componentD, LogSeverity::Debug(2)); // componentE should inherit componentD's log severity. ASSERT_TRUE(settings.shouldLog(componentE, LogSeverity::Debug(2))); ASSERT_FALSE(settings.shouldLog(componentE, LogSeverity::Debug(3))); // Clearing parent's log severity - componentE should inherit from Default. settings.clearMinimumLoggedSeverity(componentD); ASSERT_TRUE(settings.shouldLog(componentE, LogSeverity::Debug(1))); ASSERT_FALSE(settings.shouldLog(componentE, LogSeverity::Debug(2))); } // Dotted name of component includes names of ancestors. TEST_F(LogTestUnadornedEncoder, LogComponentDottedName) { // Default -> ComponentD -> ComponentE ASSERT_EQUALS(componentDefault.getShortName(), LogComponent(LogComponent::kDefault).getDottedName()); ASSERT_EQUALS(componentD.getShortName(), componentD.getDottedName()); ASSERT_EQUALS(componentD.getShortName() + "." + componentE.getShortName(), componentE.getDottedName()); } // Log names of all components should have the same length. TEST_F(LogTestUnadornedEncoder, LogComponentNameForLog) { size_t defaultNameForLogLength = componentDefault.getNameForLog().toString().length(); ASSERT_NOT_EQUALS(0U, defaultNameForLogLength); for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { LogComponent component = static_cast(i); ASSERT_EQUALS(defaultNameForLogLength, component.getNameForLog().toString().length()); } } /** * Verifies that the encoded log line contains string. */ void testEncodedLogLine(const MessageEventEphemeral& event, const std::string& expectedSubstring) { MessageEventDetailsEncoder encoder; std::ostringstream os; ASSERT_TRUE(static_cast(encoder.encode(event, os))); std::string s = os.str(); if (s.find(expectedSubstring) == std::string::npos) { FAIL() << "encoded log line does not contain substring \"" << expectedSubstring << "\". log line: " << s; } } // Log severity should always be logged as a single capital letter. TEST_F(LogTestUnadornedEncoder, MessageEventDetailsEncoderLogSeverity) { Date_t d(curTimeMillis64()); StringData ctx("WHAT", StringData::LiteralTag()); StringData msg("HUH", StringData::LiteralTag()); // Severe is indicated by (F)atal. testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Severe(), ctx, msg), " F "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Error(), ctx, msg), " E "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Warning(), ctx, msg), " W "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Info(), ctx, msg), " I "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Log(), ctx, msg), " I "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(0), ctx, msg), " I "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(1), ctx, msg), " D "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(2), ctx, msg), " D "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(3), ctx, msg), " D "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(4), ctx, msg), " D "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(5), ctx, msg), " D "); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Debug(100), ctx, msg), " D "); // Unknown severity. testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Severe().moreSevere(), ctx, msg), " U "); } // Non-default log component short name should always be logged. TEST_F(LogTestUnadornedEncoder, MessageEventDetailsEncoderLogComponent) { Date_t d(curTimeMillis64()); StringData ctx("WHAT", StringData::LiteralTag()); StringData msg("HUH", StringData::LiteralTag()); for (int i = 0; i < int(LogComponent::kNumLogComponents); ++i) { LogComponent component = static_cast(i); testEncodedLogLine(MessageEventEphemeral(d, LogSeverity::Info(), component, ctx, msg), str::stream() << " I " << component.getNameForLog() << " ["); } } // Tests pass through of log component: // log macros -> LogStreamBuilder -> MessageEventEphemeral -> MessageEventDetailsEncoder TEST_F(LogTestDetailsEncoder, ) { globalLogDomain()->setMinimumLoggedSeverity(LogSeverity::Log()); // Default log component short name should not appear in detailed log line. MONGO_LOG_COMPONENT(0, componentDefault) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(componentDefault.getNameForLog().toString()), std::string::npos); // Non-default log component short name should appear in detailed log line. _logLines.clear(); MONGO_LOG_COMPONENT(0, componentA) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(componentA.getNameForLog().toString()), std::string::npos); // MONGO_LOG_COMPONENT2 - only the first component is sent to LogStreamBuilder. _logLines.clear(); MONGO_LOG_COMPONENT2(0, componentA, componentB) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(componentA.getNameForLog().toString()), std::string::npos); ASSERT_EQUALS(_logLines[0].find(componentB.getNameForLog().toString()), std::string::npos); // MONGO_LOG_COMPONENT3 - only the first component is sent to LogStreamBuilder. _logLines.clear(); MONGO_LOG_COMPONENT3(0, componentA, componentB, componentC) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(componentA.getNameForLog().toString()), std::string::npos); ASSERT_EQUALS(_logLines[0].find(componentB.getNameForLog().toString()), std::string::npos); ASSERT_EQUALS(_logLines[0].find(componentC.getNameForLog().toString()), std::string::npos); } // Tests pass through of log component: // unconditional log functions -> LogStreamBuilder -> MessageEventEphemeral // -> MessageEventDetailsEncoder TEST_F(LogTestDetailsEncoder, LogFunctions) { // severe() - no component specified. severe() << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentDefault.getNameForLog()), std::string::npos); // severe() - with component. _logLines.clear(); severe(componentA) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentA.getNameForLog()), std::string::npos); // error() - no component specified. _logLines.clear(); error() << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentDefault.getNameForLog()), std::string::npos); // error() - with component. _logLines.clear(); error(componentA) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentA.getNameForLog()), std::string::npos); // warning() - no component specified. _logLines.clear(); warning() << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentDefault.getNameForLog()), std::string::npos); // warning() - with component. _logLines.clear(); warning(componentA) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentA.getNameForLog()), std::string::npos); // log() - no component specified. _logLines.clear(); log() << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentDefault.getNameForLog()), std::string::npos); // log() - with component. _logLines.clear(); log(componentA) << "This is logged"; ASSERT_EQUALS(1U, _logLines.size()); ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentA.getNameForLog()), std::string::npos); } } // namespace } // namespace mongo int main(int argc, char** argv) { // Ignore the client_test main since we don't want background threads when running this // test as that creates races with the testing appender created above. ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/log_test.h000066400000000000000000000047001273231111400233370ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/base/status.h" #include "mongo/logger/appender.h" #include "mongo/logger/log_severity.h" #include "mongo/logger/logger.h" #include "mongo/logger/message_log_domain.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace logger { // Used for testing logging framework only. // TODO(schwerin): Have logger write to a different log from the global log, so that tests can // redirect their global log output for examination. template class LogTest : public unittest::Test { friend class LogTestAppender; public: LogTest() : _severityOld(globalLogDomain()->getMinimumLogSeverity()) { globalLogDomain()->clearAppenders(); _appenderHandle = globalLogDomain()->attachAppender( MessageLogDomain::AppenderAutoPtr(new LogTestAppender(this))); } virtual ~LogTest() { globalLogDomain()->detachAppender(_appenderHandle); globalLogDomain()->setMinimumLoggedSeverity(_severityOld); } protected: std::vector _logLines; LogSeverity _severityOld; private: class LogTestAppender : public MessageLogDomain::EventAppender { public: explicit LogTestAppender(LogTest* ltest) : _ltest(ltest) {} virtual ~LogTestAppender() {} virtual Status append(const MessageLogDomain::Event& event) { std::ostringstream _os; if (!_encoder.encode(event, _os)) return Status(ErrorCodes::LogWriteFailed, "Failed to append to LogTestAppender."); _ltest->_logLines.push_back(_os.str()); return Status::OK(); } private: LogTest* _ltest; MessageEventEncoder _encoder; }; MessageLogDomain::AppenderHandle _appenderHandle; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/logger.cpp000066400000000000000000000030631273231111400233320ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/logger/logger.h" #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/platform/compiler.h" namespace mongo { namespace logger { static LogManager* theGlobalLogManager; // NULL at program start, before even static // initialization. LogManager* globalLogManager() { if (MONGO_unlikely(!theGlobalLogManager)) { theGlobalLogManager = new LogManager; } return theGlobalLogManager; } /** * Just in case no static initializer called globalLogManager, make sure that the global log * manager is instantiated while we're still in a single-threaded context. */ MONGO_INITIALIZER_GENERAL(GlobalLogManager, MONGO_NO_PREREQUISITES, ("default"))(InitializerContext*) { globalLogManager(); return Status::OK(); } } // namespace logger } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(logger_logger) mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/logger.h000066400000000000000000000022041273231111400227730ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/export_macros.h" #include "mongo/logger/message_log_domain.h" #include "mongo/logger/log_manager.h" namespace mongo { namespace logger { /** * Gets a global singleton instance of LogManager. */ MONGO_CLIENT_API LogManager* MONGO_CLIENT_FUNC globalLogManager(); /** * Gets the global MessageLogDomain associated for the global log manager. */ inline ComponentMessageLogDomain* globalLogDomain() { return globalLogManager()->getGlobalDomain(); } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/logstream_builder.cpp000066400000000000000000000115071273231111400255600ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/logstream_builder.h" #include "mongo/base/init.h" #include "mongo/base/owned_pointer_vector.h" #include "mongo/base/status.h" #include "mongo/logger/message_event_utf8_encoder.h" #include "mongo/logger/tee.h" #include "mongo/util/assert_util.h" // TODO: remove apple dep for this in threadlocal.h #include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/time_support.h" namespace mongo { namespace { /// Type of per-thread cache for storing pre-constructed ostringstreams. While its type is /// vector, it should only ever contain 0 or 1 item. It is a vector rather than just a /// thread_specific_ptr<> because of the high cost of thread_specific_ptr<>::reset(). typedef OwnedPointerVector OwnedOstreamVector; /// This flag indicates whether the system providing a per-thread cache of ostringstreams /// for use by LogstreamBuilder instances is initialized and ready for use. Until this /// flag is true, LogstreamBuilder instances must not use the cache. bool isThreadOstreamCacheInitialized = false; MONGO_INITIALIZER(LogstreamBuilder)(InitializerContext*) { isThreadOstreamCacheInitialized = true; return Status::OK(); } } // namespace TSP_DECLARE(OwnedOstreamVector, threadOstreamCache); TSP_DEFINE(OwnedOstreamVector, threadOstreamCache); namespace logger { LogstreamBuilder::LogstreamBuilder(MessageLogDomain* domain, const std::string& contextName, LogSeverity severity) : _domain(domain), _contextName(contextName), _severity(severity), _component(LogComponent::kDefault), _os(NULL), _tee(NULL) {} LogstreamBuilder::LogstreamBuilder(MessageLogDomain* domain, const std::string& contextName, LogSeverity severity, LogComponent component) : _domain(domain), _contextName(contextName), _severity(severity), _component(component), _os(NULL), _tee(NULL) {} LogstreamBuilder::LogstreamBuilder(logger::MessageLogDomain* domain, const std::string& contextName, LabeledLevel labeledLevel) : _domain(domain), _contextName(contextName), _severity(labeledLevel), _component(LogComponent::kDefault), _os(NULL), _tee(NULL) { setBaseMessage(labeledLevel.getLabel()); } LogstreamBuilder::LogstreamBuilder(const LogstreamBuilder& other) : _domain(other._domain), _contextName(other._contextName), _severity(other._severity), _component(other._component), _baseMessage(other._baseMessage), _os(NULL), _tee(NULL) { if (other._os || other._tee) abort(); } LogstreamBuilder::~LogstreamBuilder() { if (_os) { if (!_baseMessage.empty()) _baseMessage.push_back(' '); _baseMessage += _os->str(); MessageEventEphemeral message( curTimeMillis64(), _severity, _component, _contextName, _baseMessage); _domain->append(message); if (_tee) { _os->str(""); logger::MessageEventDetailsEncoder teeEncoder; teeEncoder.encode(message, *_os); _tee->write(_os->str()); } _os->str(""); if (isThreadOstreamCacheInitialized && threadOstreamCache.getMake()->vector().empty()) { threadOstreamCache.get()->mutableVector().push_back(_os); } else { delete _os; } } } void LogstreamBuilder::operator<<(Tee* tee) { makeStream(); // Adding a Tee counts for purposes of deciding to make a log message. // TODO: dassert(!_tee); _tee = tee; } void LogstreamBuilder::makeStream() { if (!_os) { if (isThreadOstreamCacheInitialized && !threadOstreamCache.getMake()->vector().empty()) { std::vector& oses = threadOstreamCache.get()->mutableVector(); _os = oses.back(); oses.pop_back(); } else { _os = new std::ostringstream; } } } } // namespace logger } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(logger_logstream_builder) mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/logstream_builder.h000066400000000000000000000133051273231111400252230ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include "mongo/client/export_macros.h" #include "mongo/logger/labeled_level.h" #include "mongo/logger/log_component.h" #include "mongo/logger/log_severity.h" #include "mongo/logger/message_log_domain.h" namespace mongo { namespace logger { class Tee; /** * Stream-ish object used to build and append log messages. */ class MONGO_CLIENT_API LogstreamBuilder { public: static LogSeverity MONGO_CLIENT_FUNC severityCast(int ll) { return LogSeverity::cast(ll); } static LogSeverity MONGO_CLIENT_FUNC severityCast(LogSeverity ls) { return ls; } static LabeledLevel MONGO_CLIENT_FUNC severityCast(const LabeledLevel& labeled) { return labeled; } /** * Construct a LogstreamBuilder that writes to "domain" on destruction. * * "contextName" is a short name of the thread or other context. * "severity" is the logging severity of the message. */ LogstreamBuilder(MessageLogDomain* domain, const std::string& contextName, LogSeverity severity); /** * Construct a LogstreamBuilder that writes to "domain" on destruction. * * "contextName" is a short name of the thread or other context. * "severity" is the logging severity of the message. * "component" is the primary log component of the message. */ LogstreamBuilder(MessageLogDomain* domain, const std::string& contextName, LogSeverity severity, LogComponent component); /** * Deprecated. */ LogstreamBuilder(MessageLogDomain* domain, const std::string& contextName, LabeledLevel labeledLevel); /** * Copies a LogstreamBuilder. LogstreamBuilder instances are copyable only until the first * call to stream() or operator<<. * * TODO(schwerin): After C++11 transition, replace with a move-constructor, and make * LogstreamBuilder movable. */ LogstreamBuilder(const LogstreamBuilder& other); /** * Destroys a LogstreamBuilder(). If anything was written to it via stream() or operator<<, * constructs a MessageLogDomain::Event and appends it to the associated domain. */ ~LogstreamBuilder(); /** * Sets an optional prefix for the message. */ LogstreamBuilder& setBaseMessage(const std::string& baseMessage) { _baseMessage = baseMessage; return *this; } std::ostream& stream() { makeStream(); return *_os; } LogstreamBuilder& operator<<(const char* x) { stream() << x; return *this; } LogstreamBuilder& operator<<(const std::string& x) { stream() << x; return *this; } LogstreamBuilder& operator<<(const StringData& x) { stream() << x; return *this; } LogstreamBuilder& operator<<(char* x) { stream() << x; return *this; } LogstreamBuilder& operator<<(char x) { stream() << x; return *this; } LogstreamBuilder& operator<<(int x) { stream() << x; return *this; } LogstreamBuilder& operator<<(long x) { stream() << x; return *this; } LogstreamBuilder& operator<<(unsigned long x) { stream() << x; return *this; } LogstreamBuilder& operator<<(unsigned x) { stream() << x; return *this; } LogstreamBuilder& operator<<(unsigned short x) { stream() << x; return *this; } LogstreamBuilder& operator<<(double x) { stream() << x; return *this; } LogstreamBuilder& operator<<(void* x) { stream() << x; return *this; } LogstreamBuilder& operator<<(const void* x) { stream() << x; return *this; } LogstreamBuilder& operator<<(long long x) { stream() << x; return *this; } LogstreamBuilder& operator<<(unsigned long long x) { stream() << x; return *this; } LogstreamBuilder& operator<<(bool x) { stream() << x; return *this; } template LogstreamBuilder& operator<<(const T& x) { stream() << x.toString(); return *this; } LogstreamBuilder& operator<<(std::ostream&(MONGO_CLIENT_FUNC* manip)(std::ostream&)) { stream() << manip; return *this; } LogstreamBuilder& operator<<(std::ios_base&(MONGO_CLIENT_FUNC* manip)(std::ios_base&)) { stream() << manip; return *this; } /** * In addition to appending the message to _domain, write it to the given tee. May only * be called once per instance of LogstreamBuilder. */ void operator<<(Tee* tee); private: LogstreamBuilder& operator=(const LogstreamBuilder& other); void makeStream(); MessageLogDomain* _domain; std::string _contextName; LogSeverity _severity; LogComponent _component; std::string _baseMessage; std::ostringstream* _os; Tee* _tee; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/message_event.h000066400000000000000000000045031273231111400243450ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/string_data.h" #include "mongo/logger/log_component.h" #include "mongo/logger/log_severity.h" #include "mongo/platform/cstdint.h" #include "mongo/util/time_support.h" namespace mongo { namespace logger { /** * Free form text log message object that does not own the storage behind its message and * contextName. * * Used and owned by one thread. This is the message type used by MessageLogDomain. */ class MessageEventEphemeral { public: MessageEventEphemeral(Date_t date, LogSeverity severity, StringData contextName, StringData message) : _date(date), _severity(severity), _component(LogComponent::kDefault), _contextName(contextName), _message(message) {} MessageEventEphemeral(Date_t date, LogSeverity severity, LogComponent component, StringData contextName, StringData message) : _date(date), _severity(severity), _component(component), _contextName(contextName), _message(message) {} uint64_t getDate() const { return _date; } LogSeverity getSeverity() const { return _severity; } LogComponent getComponent() const { return _component; } StringData getContextName() const { return _contextName; } StringData getMessage() const { return _message; } private: Date_t _date; LogSeverity _severity; LogComponent _component; StringData _contextName; StringData _message; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/message_event_utf8_encoder.cpp000066400000000000000000000061251273231111400273470ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/message_event_utf8_encoder.h" #include #include "mongo/util/time_support.h" namespace mongo { namespace logger { static MessageEventDetailsEncoder::DateFormatter _dateFormatter = outputDateAsISOStringLocal; void MessageEventDetailsEncoder::setDateFormatter(DateFormatter dateFormatter) { _dateFormatter = dateFormatter; } MessageEventDetailsEncoder::DateFormatter MessageEventDetailsEncoder::getDateFormatter() { return _dateFormatter; } MessageEventDetailsEncoder::~MessageEventDetailsEncoder() {} std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& event, std::ostream& os) { static const size_t maxLogLine = 10 * 1024; _dateFormatter(os, event.getDate()); os << ' '; os << event.getSeverity().toChar(); os << ' '; LogComponent component = event.getComponent(); os << component; os << ' '; StringData contextName = event.getContextName(); if (!contextName.empty()) { os << '[' << contextName << "] "; } StringData msg = event.getMessage(); if (msg.size() > maxLogLine) { os << "warning: log line attempted (" << msg.size() / 1024 << "k) over max size (" << maxLogLine / 1024 << "k), printing beginning and end ... "; os << msg.substr(0, maxLogLine / 3); os << " .......... "; os << msg.substr(msg.size() - (maxLogLine / 3)); } else { os << msg; } if (!msg.endsWith(StringData("\n", StringData::LiteralTag()))) os << '\n'; return os; } MessageEventWithContextEncoder::~MessageEventWithContextEncoder() {} std::ostream& MessageEventWithContextEncoder::encode(const MessageEventEphemeral& event, std::ostream& os) { StringData contextName = event.getContextName(); if (!contextName.empty()) { os << '[' << contextName << "] "; } StringData message = event.getMessage(); os << message; if (!message.endsWith("\n")) os << '\n'; return os; } MessageEventUnadornedEncoder::~MessageEventUnadornedEncoder() {} std::ostream& MessageEventUnadornedEncoder::encode(const MessageEventEphemeral& event, std::ostream& os) { StringData message = event.getMessage(); os << message; if (!message.endsWith("\n")) os << '\n'; return os; } } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/message_event_utf8_encoder.h000066400000000000000000000044061273231111400270140ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/logger/encoder.h" #include "mongo/logger/message_event.h" #include "mongo/util/time_support.h" namespace mongo { namespace logger { /** * Encoder that writes log messages of the style that MongoDB writes to console and files. */ class MessageEventDetailsEncoder : public Encoder { public: typedef void (*DateFormatter)(std::ostream&, Date_t); /** * Sets the date formatter function for all instances of MessageEventDetailsEncoder. * * Only and always safe to call during single-threaded execution, as in during start-up * intiailization. */ static void setDateFormatter(DateFormatter dateFormatter); /** * Gets the date formatter function in use by instances of MessageEventDetailsEncoder. * * Always safe to call. */ static DateFormatter getDateFormatter(); virtual ~MessageEventDetailsEncoder(); virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os); }; /** * Encoder that generates log messages suitable for syslog. */ class MessageEventWithContextEncoder : public Encoder { public: virtual ~MessageEventWithContextEncoder(); virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os); }; /** * Encoder that generates log messages containing only the raw text of the message. */ class MessageEventUnadornedEncoder : public Encoder { public: virtual ~MessageEventUnadornedEncoder(); virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os); }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/message_log_domain.cpp000066400000000000000000000015741273231111400256740ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/logger/message_log_domain.h" #include "mongo/logger/log_domain-impl.h" namespace mongo { namespace logger { template class MONGO_CLIENT_API LogDomain; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/message_log_domain.h000066400000000000000000000016541273231111400253400ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/logger/log_domain.h" #include "mongo/logger/message_event.h" namespace mongo { namespace logger { typedef LogDomain MessageLogDomain; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/logger/tee.h000066400000000000000000000017641273231111400223030ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include namespace mongo { namespace logger { class Tee { public: virtual ~Tee() {} /** * Implementations of Tee::write must handle their own synchronization. Callers may assume * it is safe to call this method at any time from any thread. */ virtual void write(const std::string& str) = 0; }; } // namespace logger } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/000077500000000000000000000000001273231111400227525ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/mongo_resource.cpp000066400000000000000000000040031273231111400265010ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/orchestration/mongo_resource.h" #include "mongo/util/mongoutils/str.h" #include namespace mongo { namespace orchestration { MongoResource::MongoResource(const std::string& url) : Resource(url) {} void MongoResource::destroy() { del(); } RestClient::response MongoResource::status() const { return get(); } RestClient::response MongoResource::action(const std::string& action) { Json::Value doc; Json::FastWriter writer; doc["action"] = action; return post("", writer.write(doc)); } std::string MongoResource::uri() const { // mongodb_uri has the format: mongodb://[/stuff not in standalones] std::string uri = handleResponse(status())["mongodb_uri"].asString(); const std::string prefix("mongodb://"); if (uri.substr(0, prefix.size()) != prefix) { throw std::runtime_error(str::stream() << "mongodb_uri does not begin with prefix 'mongodb://'" << ", got: " << uri); } uri = uri.substr(prefix.size()); const size_t suffix = uri.find('/'); return uri.substr(0, suffix); } std::string MongoResource::mongodbUri() const { Document response = handleResponse(status()); if (response.isMember("mongodb_auth_uri")) { return response["mongodb_auth_uri"].asString(); } return response["mongodb_uri"].asString(); } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/mongo_resource.h000066400000000000000000000020441273231111400261510ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/orchestration/resource.h" namespace mongo { namespace orchestration { class MongoResource : public Resource { public: void destroy(); std::string uri() const; std::string mongodbUri() const; RestClient::response action(const std::string& action); protected: MongoResource(const std::string& url); RestClient::response status() const; }; } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/replica_set.cpp000066400000000000000000000027761273231111400257640ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/orchestration/replica_set.h" #include namespace { const std::string kResourceName = "replica_sets"; } namespace mongo { namespace orchestration { ReplicaSet::ReplicaSet(const std::string& url) : MongoResource(url) {} Server ReplicaSet::primary() const { Document doc = handleResponse(get("primary")); std::string server_id = doc["server_id"].asString(); std::string url = Server::resourceName().append("/").append(server_id); return Server(baseRelativeUrl(url)); } std::vector ReplicaSet::secondaries() const { return pluralResource("secondaries"); } std::vector ReplicaSet::hidden() const { return pluralResource("hidden"); } std::vector ReplicaSet::arbiters() const { return pluralResource("arbiters"); } std::string ReplicaSet::resourceName() { return kResourceName; } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/replica_set.h000066400000000000000000000022761273231111400254240ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/orchestration/mongo_resource.h" #include "mongo/orchestration/server.h" namespace mongo { namespace orchestration { class ReplicaSet : public MongoResource { friend class Resource; friend class Service; friend class Cluster; public: Server primary() const; std::vector secondaries() const; std::vector arbiters() const; std::vector hidden() const; std::vector members() const; static std::string resourceName(); private: ReplicaSet(const std::string& url); }; } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/resource.cpp000066400000000000000000000057201273231111400253110ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongo/orchestration/resource.h" namespace mongo { namespace orchestration { using std::cout; using std::endl; namespace { const char content_type[] = "text/json"; const std::string kResourceName; enum Status { OK = 200, NoContent = 204, BadRequest = 400, NotFound = 404, InternalServerError = 500 }; } // namespace Resource::Resource(const std::string& url) : _url(url) {} Resource::~Resource() {} RestClient::response Resource::get(const std::string& relative_path) const { // std::cout << "[GET] " << relativeUrl(relative_path) << std::endl; return RestClient::get(relativeUrl(relative_path)); } RestClient::response Resource::put(const std::string& relative_path, const std::string& payload) { // std::cout << "[PUT] " << relativeUrl(relative_path) << std::endl; return RestClient::put(relativeUrl(relative_path), content_type, payload); } RestClient::response Resource::post(const std::string& relative_path, const std::string& payload) { // std::cout << "[POST] " << relativeUrl(relative_path) << std::endl; return RestClient::post(relativeUrl(relative_path), content_type, payload); } RestClient::response Resource::del(const std::string& relative_path) { // std::cout << "[DEL] " << relativeUrl(relative_path) << std::endl; return RestClient::del(relativeUrl(relative_path)); } std::string Resource::url() const { return _url; } std::string Resource::relativeUrl(const std::string& relative_path) const { return relative_path.empty() ? _url : _url + "/" + relative_path; } std::string Resource::baseRelativeUrl(const std::string& relative_path) const { std::string base = _url.substr(0, _url.find("/") + 1); return relative_path.empty() ? base : base.append(relative_path); } Document Resource::handleResponse(const RestClient::response& response) const { Document doc; if (response.code == OK) { Json::Reader reader; bool parseSuccessful = reader.parse(response.body.c_str(), doc); if (!parseSuccessful) throw std::runtime_error("[orchestration] Failed parsing response: " + response.body); } else if (response.code != NoContent) { throw std::runtime_error("[orchestration] Bad response: " + response.body); } return doc; } std::string Resource::resourceName() { return kResourceName; } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/resource.h000066400000000000000000000045221273231111400247550ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "third_party/jsoncpp/json.h" #include "third_party/restclient/restclient.h" // Notes: // Posts to resources must not end with a slash or you will get a 404 // Posts containing a JSON encoded body must conform to strict JSON namespace mongo { namespace orchestration { typedef Json::Value Document; class Resource { public: Resource(const std::string& url); virtual ~Resource(); protected: RestClient::response get(const std::string& relative_path = "") const; RestClient::response put(const std::string& relative_path = "", const std::string& payload = "{}"); RestClient::response post(const std::string& relative_path = "", const std::string& payload = "{}"); RestClient::response del(const std::string& relative_path = ""); std::string url() const; std::string relativeUrl(const std::string& relative_path) const; std::string baseRelativeUrl(const std::string& relative_path) const; Document handleResponse(const RestClient::response& response) const; static std::string resourceName(); template std::vector pluralResource(const std::string& resource_name) const { std::vector resources; Document doc = handleResponse(get(resource_name)); for (unsigned i = 0; i < doc.size(); i++) { std::string server_id = doc[resource_name][i]["server_id"].asString(); std::string url = T::resourceName().append("/").append(server_id); T resource(baseRelativeUrl(url)); resources.push_back(resource); } return resources; } private: std::string _url; }; } // namespace orchestration } // namesace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/server.cpp000066400000000000000000000020511273231111400247620ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/orchestration/server.h" namespace { const std::string kResourceName = "servers"; } namespace mongo { namespace orchestration { Server::Server(const std::string& url) : MongoResource(url) {} void Server::start() { action("start"); } void Server::stop() { action("stop"); } void Server::restart() { action("restart"); } std::string Server::resourceName() { return kResourceName; } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/server.h000066400000000000000000000020361273231111400244320ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/orchestration/mongo_resource.h" namespace mongo { namespace orchestration { class Server : public MongoResource { friend class Resource; friend class Service; friend class ReplicaSet; friend class Cluster; public: void start(); void stop(); void restart(); static std::string resourceName(); private: Server(const std::string& url); }; } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/service.cpp000066400000000000000000000043361273231111400251240ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/orchestration/service.h" namespace mongo { namespace orchestration { namespace { const char kRequiredVersion[] = "0.9"; const char kAPIVersion[] = "v1"; const char kServers[] = "servers"; const char kReplicaSets[] = "replica_sets"; const char kShardedClusters[] = "sharded_clusters"; } // namespace Service::Service(const std::string& url) : Resource(url) {} std::vector Service::servers() const { return pluralResource(kServers); } std::vector Service::replica_sets() const { return pluralResource(kReplicaSets); } std::vector Service::clusters() const { return pluralResource(kShardedClusters); } Server Service::server(const std::string& id) const { return Server(relativeUrl(std::string(kServers).append("/").append(id))); } ReplicaSet Service::replicaSet(const std::string& id) const { return ReplicaSet(relativeUrl(std::string(kReplicaSets).append("/").append(id))); } std::string Service::createMongod(const Document& params) { return _createResource(kServers, params); } std::string Service::createReplicaSet(const Document& params) { return _createResource(kReplicaSets, params); } std::string Service::createShardedCluster(const Document& params) { return _createResource(kShardedClusters, params); } std::string Service::_createResource(const char resource[], const Document& params) { Json::FastWriter writer; RestClient::response result = post(resource, writer.write(params)); Document result_doc = handleResponse(result); return result_doc["id"].asString(); } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/service.h000066400000000000000000000031711273231111400245650ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/orchestration/resource.h" #include "mongo/orchestration/replica_set.h" #include "mongo/orchestration/server.h" #include "mongo/orchestration/sharded_cluster.h" namespace mongo { namespace orchestration { class Service : public Resource { public: explicit Service(const std::string& url); std::vector servers() const; std::vector replica_sets() const; std::vector clusters() const; std::string createMongod(const Document& params = Document()); std::string createMongos(const Document& params = Document()); std::string createReplicaSet(const Document& params = Document()); std::string createShardedCluster(const Document& params = Document()); Server server(const std::string& id) const; ReplicaSet replicaSet(const std::string& id) const; ShardedCluster shardedCluster(const std::string& id) const; private: std::string _createResource(const char resource[], const Document& params); }; } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/sharded_cluster.cpp000066400000000000000000000023711273231111400266340ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/orchestration/sharded_cluster.h" namespace { const std::string kResourceName = "sharded_clusters"; } namespace mongo { namespace orchestration { ShardedCluster::ShardedCluster(const std::string& url) : MongoResource(url) {} std::vector ShardedCluster::members() const { return pluralResource("members"); } std::vector ShardedCluster::configs() const { return pluralResource("configs"); } std::vector ShardedCluster::routers() const { return pluralResource("routers"); } std::string ShardedCluster::resourceName() { return kResourceName; } } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/orchestration/sharded_cluster.h000066400000000000000000000021431273231111400262760ustar00rootroot00000000000000/** * Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/orchestration/mongo_resource.h" #include "mongo/orchestration/server.h" namespace mongo { namespace orchestration { class ShardedCluster : public MongoResource { friend class Resource; friend class Service; public: std::vector members() const; std::vector configs() const; std::vector routers() const; static std::string resourceName(); private: ShardedCluster(const std::string& url); }; } // namespace orchestration } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/000077500000000000000000000000001273231111400217125ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_intrinsics.h000066400000000000000000000043671273231111400256160ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * NOTE: Not for direct use by any code other than AtomicWord. * * The atomic_intrinsics module provides low-level atomic operations for manipulating memory. * Implementations are platform specific, so this file describes the interface and includes * the appropriate os/compiler-specific headers. * * For supported word types, the atomic_intrinsics headers provide implementations of template * classes of the following form: * * template class AtomicIntrinsics { * static T load(volatile const T* value); * static T store(volatile T* dest, T newValue); * static T compareAndSwap(volatile T* dest, T expected, T newValue); * static T swap(volatile T* dest, T newValue); * static T fetchAndAdd(volatile T* dest, T increment); * }; * * All of the functions assume that the volatile T pointers are naturally aligned, and may not * operate as expected, if they are not so aligned. * * The behavior of the functions is analogous to the same-named member functions of the AtomicWord * template type in atomic_word.h. */ #pragma once #include "mongo/config.h" #if defined(MONGO_HAVE_CXX11_ATOMICS) #error "Use of atomic_intrinsics.h is not supported when C++11 is available" #endif #if defined(_WIN32) #include "mongo/platform/atomic_intrinsics_win32.h" #elif defined(MONGO_HAVE_GCC_ATOMIC_BUILTINS) #include "mongo/platform/atomic_intrinsics_gcc_atomic.h" #elif defined(MONGO_HAVE_GCC_SYNC_BUILTINS) #include "mongo/platform/atomic_intrinsics_gcc_sync.h" #elif defined(__i386__) || defined(__x86_64__) #include "mongo/platform/atomic_intrinsics_gcc_intel.h" #else #error "Unsupported os/compiler family" #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_intrinsics_gcc_atomic.h000066400000000000000000000037141273231111400277610ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Implementation of the AtomicIntrinsics::* operations for systems on any * architecture using a new enough GCC-compatible compiler toolchain. */ #pragma once namespace mongo { /** * Instantiation of AtomicIntrinsics<> for all word types T. */ template class AtomicIntrinsics { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { __atomic_compare_exchange( dest, &expected, &newValue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } static T swap(volatile T* dest, T newValue) { T result; __atomic_exchange(dest, &newValue, &result, __ATOMIC_SEQ_CST); return result; } static T load(volatile const T* value) { T result; __atomic_load(value, &result, __ATOMIC_SEQ_CST); return result; } static T loadRelaxed(volatile const T* value) { T result; __atomic_load(value, &result, __ATOMIC_RELAXED); return result; } static void store(volatile T* dest, T newValue) { __atomic_store(dest, &newValue, __ATOMIC_SEQ_CST); } static T fetchAndAdd(volatile T* dest, T increment) { return __atomic_fetch_add(dest, increment, __ATOMIC_SEQ_CST); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_intrinsics_gcc_intel.h000066400000000000000000000110601273231111400276110ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Implementation of the AtomicIntrinsics::* operations for IA-32 and AMD64 systems using a * GCC-compatible compiler toolchain. */ #pragma once #include namespace mongo { /** * Instantiation of AtomicIntrinsics<> for all word types T where sizeof <= sizeof(void *). * * On 32-bit systems, this handles 8-, 16- and 32-bit word types. On 64-bit systems, * it handles 8-, 16, 32- and 64-bit types. */ template class AtomicIntrinsics { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { T result; asm volatile("lock cmpxchg %[src], %[dest]" : [dest] "+m"(*dest), "=a"(result) : [src] "r"(newValue), "a"(expected) : "memory", "cc"); return result; } static T swap(volatile T* dest, T newValue) { T result = newValue; // No need for "lock" prefix on "xchg". asm volatile("xchg %[r], %[dest]" : [dest] "+m"(*dest), [r] "+r"(result) : : "memory"); return result; } static T load(volatile const T* value) { asm volatile("mfence" ::: "memory"); T result = *value; asm volatile("mfence" ::: "memory"); return result; } static T loadRelaxed(volatile const T* value) { return *value; } static void store(volatile T* dest, T newValue) { asm volatile("mfence" ::: "memory"); *dest = newValue; asm volatile("mfence" ::: "memory"); } static T fetchAndAdd(volatile T* dest, T increment) { T result = increment; asm volatile("lock xadd %[src], %[dest]" : [dest] "+m"(*dest), [src] "+r"(result) : : "memory", "cc"); return result; } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; /** * Instantiation of AtomicIntrinsics where sizeof exceeds sizeof(void*). * * On 32-bit systems, this handles the 64-bit word type. Not used on 64-bit systems. * * Note that the implementations of swap, store and fetchAndAdd spin until they succeed. This * implementation is thread-safe, but may have poor performance in high-contention environments. * However, no superior solution exists for IA-32 (32-bit x86) systems. */ template class AtomicIntrinsics::type> { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { T result = expected; asm volatile( "push %%eax\n" "push %%ebx\n" "push %%ecx\n" "push %%edx\n" "mov (%%edx), %%ebx\n" "mov 4(%%edx), %%ecx\n" "mov (%%edi), %%eax\n" "mov 4(%%edi), %%edx\n" "lock cmpxchg8b (%%esi)\n" "mov %%eax, (%%edi)\n" "mov %%edx, 4(%%edi)\n" "pop %%edx\n" "pop %%ecx\n" "pop %%ebx\n" "pop %%eax\n" : : "S"(dest), "D"(&result), "d"(&newValue) : "memory", "cc"); return result; } static T swap(volatile T* dest, T newValue) { T expected; T actual; do { expected = *dest; actual = compareAndSwap(dest, expected, newValue); } while (actual != expected); return actual; } static T load(volatile const T* value) { return compareAndSwap(const_cast(value), T(0), T(0)); } static void store(volatile T* dest, T newValue) { swap(dest, newValue); } static T fetchAndAdd(volatile T* dest, T increment) { T expected; T actual; do { expected = load(dest); actual = compareAndSwap(dest, expected, expected + increment); } while (actual != expected); return actual; } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_intrinsics_gcc_sync.h000066400000000000000000000057401273231111400274620ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Implementation of the AtomicIntrinsics::* operations for systems on any * architecture using a GCC 4.1+ compatible compiler toolchain. */ #pragma once #include namespace mongo { /** * Instantiation of AtomicIntrinsics<> for all word types T. */ template class AtomicIntrinsics { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { return __sync_val_compare_and_swap(dest, expected, newValue); } static T swap(volatile T* dest, T newValue) { T currentValue = *dest; while (true) { const T result = compareAndSwap(dest, currentValue, newValue); if (result == currentValue) return result; currentValue = result; } } static T load(volatile const T* value) { __sync_synchronize(); T result = *value; __sync_synchronize(); return result; } static T loadRelaxed(volatile const T* value) { asm volatile("" ::: "memory"); return *value; } static void store(volatile T* dest, T newValue) { __sync_synchronize(); *dest = newValue; __sync_synchronize(); } static T fetchAndAdd(volatile T* dest, T increment) { return __sync_fetch_and_add(dest, increment); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; template class AtomicIntrinsics::type> { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { return __sync_val_compare_and_swap(dest, expected, newValue); } static T swap(volatile T* dest, T newValue) { T currentValue = *dest; while (true) { const T result = compareAndSwap(dest, currentValue, newValue); if (result == currentValue) return result; currentValue = result; } } static T load(volatile const T* value) { return compareAndSwap(const_cast(value), T(0), T(0)); } static void store(volatile T* dest, T newValue) { swap(dest, newValue); } static T fetchAndAdd(volatile T* dest, T increment) { return __sync_fetch_and_add(dest, increment); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_intrinsics_win32.h000066400000000000000000000172351273231111400266360ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Implementation of the AtomicIntrinsics::* operations for Windows systems. */ #pragma once #include #include "mongo/platform/windows_basic.h" #include #pragma intrinsic(_InterlockedCompareExchange64) namespace mongo { /** * Default instantiation of AtomicIntrinsics<>, for unsupported types. */ template class AtomicIntrinsics { private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; /** * Instantiation of AtomicIntrinsics<> for 32-bit word sizes (i.e., unsigned). */ template class AtomicIntrinsics::type> { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { return InterlockedCompareExchange( reinterpret_cast(dest), LONG(newValue), LONG(expected)); } static T swap(volatile T* dest, T newValue) { return InterlockedExchange(reinterpret_cast(dest), LONG(newValue)); } static T load(volatile const T* value) { MemoryBarrier(); T result = *value; MemoryBarrier(); return result; } static T loadRelaxed(volatile const T* value) { return *value; } static void store(volatile T* dest, T newValue) { MemoryBarrier(); *dest = newValue; MemoryBarrier(); } static T fetchAndAdd(volatile T* dest, T increment) { return InterlockedExchangeAdd(reinterpret_cast(dest), LONG(increment)); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; namespace details { template struct InterlockedImpl64; // Implementation of 64-bit Interlocked operations via Windows API calls. template struct InterlockedImpl64 { static T compareAndSwap(volatile T* dest, T expected, T newValue) { return InterlockedCompareExchange64( reinterpret_cast(dest), LONGLONG(newValue), LONGLONG(expected)); } static T swap(volatile T* dest, T newValue) { return InterlockedExchange64(reinterpret_cast(dest), LONGLONG(newValue)); } static T fetchAndAdd(volatile T* dest, T increment) { return InterlockedExchangeAdd64(reinterpret_cast(dest), LONGLONG(increment)); } }; // Implementation of 64-bit Interlocked operations for systems where the API does not // yet provide the Interlocked...64 operations. template struct InterlockedImpl64 { static T compareAndSwap(volatile T* dest, T expected, T newValue) { // NOTE: We must use the compiler intrinsic here: WinXP does not offer // InterlockedCompareExchange64 as an API call. return _InterlockedCompareExchange64( reinterpret_cast(dest), LONGLONG(newValue), LONGLONG(expected)); } static T swap(volatile T* dest, T newValue) { // NOTE: You may be tempted to replace this with // 'InterlockedExchange64'. Resist! It will compile just fine despite not being // listed in the docs as available on XP, but the compiler may replace it with // calls to the non-intrinsic 'InterlockedCompareExchange64', which does not // exist on XP. We work around this by rolling our own synthetic in terms of // compareAndSwap which we have explicitly formulated in terms of the compiler // provided _InterlockedCompareExchange64 intrinsic. T currentValue = *dest; while (true) { const T result = compareAndSwap(dest, currentValue, newValue); if (result == currentValue) return result; currentValue = result; } } static T fetchAndAdd(volatile T* dest, T increment) { // NOTE: See note for 'swap' on why we roll this ourselves. T currentValue = *dest; while (true) { const T incremented = currentValue + increment; const T result = compareAndSwap(dest, currentValue, incremented); if (result == currentValue) return result; currentValue = result; } } }; // On 32-bit IA-32 systems, 64-bit load and store must be implemented in terms of // Interlocked operations, but on 64-bit systems they support a simpler, native // implementation. The LoadStoreImpl type represents the abstract implementation of // loading and storing 64-bit values. template struct LoadStoreImpl; // Implementation on 64-bit systems. template struct LoadStoreImpl::type> { static U load(volatile const U* value) { MemoryBarrier(); U result = *value; MemoryBarrier(); return result; } static void store(volatile U* dest, U newValue) { MemoryBarrier(); *dest = newValue; MemoryBarrier(); } }; // Implementation on 32-bit systems. template struct LoadStoreImpl::type> { // NOTE: Implemented out-of-line below since the implementation relies on // AtomicIntrinsics. static U load(volatile const U* value); static void store(volatile U* dest, U newValue); }; } // namespace details /** * Instantiation of AtomicIntrinsics<> for 64-bit word sizes. */ template class AtomicIntrinsics::type> { public: #if defined(NTDDI_VERSION) && defined(NTDDI_WS03SP2) && (NTDDI_VERSION >= NTDDI_WS03SP2) static const bool kHaveInterlocked64 = true; #else static const bool kHaveInterlocked64 = false; #endif typedef details::InterlockedImpl64 InterlockedImpl; typedef details::LoadStoreImpl LoadStoreImpl; static T compareAndSwap(volatile T* dest, T expected, T newValue) { return InterlockedImpl::compareAndSwap(dest, expected, newValue); } static T swap(volatile T* dest, T newValue) { return InterlockedImpl::swap(dest, newValue); } static T load(volatile const T* value) { return LoadStoreImpl::load(value); } static void store(volatile T* dest, T newValue) { LoadStoreImpl::store(dest, newValue); } static T fetchAndAdd(volatile T* dest, T increment) { return InterlockedImpl::fetchAndAdd(dest, increment); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; namespace details { template U LoadStoreImpl::type>::load( volatile const U* value) { return AtomicIntrinsics::compareAndSwap(const_cast(value), U(0), U(0)); } template void LoadStoreImpl::type>::store( volatile U* dest, U newValue) { AtomicIntrinsics::swap(dest, newValue); } } // namespace details } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_word.h000066400000000000000000000014471273231111400244000ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #if defined(MONGO_HAVE_CXX11_ATOMICS) #include "mongo/platform/atomic_word_cxx11.h" #else #include "mongo/platform/atomic_word_intrinsics.h" #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_word_cxx11.h000066400000000000000000000130121273231111400254130ustar00rootroot00000000000000/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if !defined(MONGO_HAVE_CXX11_ATOMICS) #error "Cannot use atomic_word_cxx11.h without C++11 support" #endif // This file is a bit unusual. Most other source files in this codebase assume that C++11 // things are only usable if __cplusplus >= 201103L. However, we have made an explicit decision // to use when available, even if full C++11 conformance is not advertised. As a // result, we unconditionally include , but guard all other C++11 features under // __cplusplus >= 201103L so that we can work on platforms that don't yet offer those features, but // do offer #include #if __cplusplus >= 201103L #include #endif #include #include "mongo/base/disallow_copying.h" namespace mongo { /** * Implementation of the AtomicWord interface in terms of the C++11 Atomics. */ template class AtomicWord { #if __cplusplus < 201103L // AtomicWords are not copyable in C++03. MONGO_DISALLOW_COPYING(AtomicWord); #endif public: /** * Underlying value type. */ typedef _WordType WordType; /** * Construct a new word with the given initial value. */ explicit AtomicWord(WordType value = WordType(0)) : _value(value) {} #if __cplusplus >= 201103L // In C++11, AtomicWords are not copyable or movable. AtomicWord(const AtomicWord&) = delete; AtomicWord& operator=(const AtomicWord&) = delete; AtomicWord(AtomicWord&&) = delete; AtomicWord& operator=(AtomicWord&&) = delete; #endif /** * Gets the current value of this AtomicWord. * * Has acquire and release semantics. */ WordType load() const { return _value.load(); } /** * Gets the current value of this AtomicWord. * * Has relaxed semantics. */ WordType loadRelaxed() const { return _value.load(std::memory_order_relaxed); } /** * Sets the value of this AtomicWord to "newValue". * * Has acquire and release semantics. */ void store(WordType newValue) { return _value.store(newValue); } /** * Atomically swaps the current value of this with "newValue". * * Returns the old value. * * Has acquire and release semantics. */ WordType swap(WordType newValue) { return _value.exchange(newValue); } /** * Atomic compare and swap. * * If this value equals "expected", sets this to "newValue". * Always returns the original of this. * * Has acquire and release semantics. */ WordType compareAndSwap(WordType expected, WordType newValue) { // NOTE: Subtle: compare_exchange mutates its first argument. _value.compare_exchange_strong(expected, newValue); return expected; } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this before incrementing. * * Has acquire and release semantics. */ WordType fetchAndAdd(WordType increment) { return _value.fetch_add(increment); } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this before decrementing. * * Has acquire and release semantics. */ WordType fetchAndSubtract(WordType decrement) { return _value.fetch_sub(decrement); } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this after incrementing. * * Has acquire and release semantics. */ WordType addAndFetch(WordType increment) { return fetchAndAdd(increment) + increment; } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this after decrementing. * * Has acquire and release semantics. */ WordType subtractAndFetch(WordType decrement) { return fetchAndSubtract(decrement) - decrement; } private: std::atomic _value; }; #if __cplusplus >= 201103L #define _ATOMIC_WORD_DECLARE(NAME, WTYPE) \ typedef class AtomicWord NAME; \ namespace { \ BOOST_STATIC_ASSERT(sizeof(NAME) == sizeof(WTYPE)); \ BOOST_STATIC_ASSERT(std::is_standard_layout::value); \ } // namespace #else #define _ATOMIC_WORD_DECLARE(NAME, WTYPE) \ typedef class AtomicWord NAME; \ namespace { \ BOOST_STATIC_ASSERT(sizeof(NAME) == sizeof(WTYPE)); \ } // namespace #endif _ATOMIC_WORD_DECLARE(AtomicUInt32, unsigned) _ATOMIC_WORD_DECLARE(AtomicUInt64, unsigned long long) _ATOMIC_WORD_DECLARE(AtomicInt32, int) _ATOMIC_WORD_DECLARE(AtomicInt64, long long) #undef _ATOMIC_WORD_DECLARE } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_word_intrinsics.h000066400000000000000000000122551273231111400266440ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" #include "mongo/platform/atomic_intrinsics.h" #include "mongo/platform/compiler.h" namespace mongo { /** * Template type for word types supporting indivisible memory operations, implemented * in terms of the atomic_intrinsics header. * * Effects of operations with "acquire" semantics are visible to other threads before effects of * any subsequent operation by the calling thread. Effects of operations with "release" * semantics are visible to other processors only after the effects of previous operations on * the current thread are visible. * * NOTE(schwerin): This implementation assumes that instances are naturally aligned. * Instances that are not naturally aligned may operate incorrectly, or not at all. Natural * alignment for this purpose means that the byte address of the beginning of the object is an * integer multiple of the size of the type, in bytes. * * NOTE(schwerin): This is a low level concurrency type, it is very hard to use correctly, and * you should not decide to use it lightly. * * NOTE(schwerin): This type is and must be a POD type, or per C++11 rules, a "Standard-layout" * type. */ template class AtomicWord { MONGO_DISALLOW_COPYING(AtomicWord); public: /** * Underlying value type. */ typedef _WordType WordType; /** * Construct a new word with the given initial value. */ explicit AtomicWord(WordType value = WordType(0)) : _value(value) {} /** * Gets the current value of this AtomicWord. * * Has acquire and release semantics. */ WordType load() const { return AtomicIntrinsics::load(&_value); } /** * Gets the current value of this AtomicWord. * * Has relaxed semantics. */ WordType loadRelaxed() const { return AtomicIntrinsics::loadRelaxed(&_value); } /** * Sets the value of this AtomicWord to "newValue". * * Has acquire and release semantics. */ void store(WordType newValue) { AtomicIntrinsics::store(&_value, newValue); } /** * Atomically swaps the current value of this with "newValue". * * Returns the old value. * * Has acquire and release semantics. */ WordType swap(WordType newValue) { return AtomicIntrinsics::swap(&_value, newValue); } /** * Atomic compare and swap. * * If this value equals "expected", sets this to "newValue". * Always returns the original of this. * * Has acquire and release semantics. */ WordType compareAndSwap(WordType expected, WordType newValue) { return AtomicIntrinsics::compareAndSwap(&_value, expected, newValue); } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this before incrementing. * * Has acquire and release semantics. */ WordType fetchAndAdd(WordType increment) { return AtomicIntrinsics::fetchAndAdd(&_value, increment); } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this before decrementing. * * Has acquire and release semantics. */ WordType fetchAndSubtract(WordType decrement) { return fetchAndAdd(WordType(0) - decrement); } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this after incrementing. * * Has acquire and release semantics. */ WordType addAndFetch(WordType increment) { return fetchAndAdd(increment) + increment; } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this after decrementing. * * Has acquire and release semantics. */ WordType subtractAndFetch(WordType decrement) { return fetchAndSubtract(decrement) - decrement; } private: volatile WordType _value; }; #define _ATOMIC_WORD_DECLARE(NAME, WTYPE) \ typedef class AtomicWord NAME; \ namespace { \ BOOST_STATIC_ASSERT(sizeof(NAME) == sizeof(WTYPE)); \ } _ATOMIC_WORD_DECLARE(AtomicUInt32, unsigned); _ATOMIC_WORD_DECLARE(AtomicUInt64, unsigned long long); _ATOMIC_WORD_DECLARE(AtomicInt32, int); _ATOMIC_WORD_DECLARE(AtomicInt64, long long); #undef _ATOMIC_WORD_DECLARE } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/atomic_word_test.cpp000066400000000000000000000074361273231111400257760ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include #include #include "mongo/platform/atomic_word.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { template void testAtomicWordBasicOperations() { typedef typename _AtomicWordType::WordType WordType; _AtomicWordType w; ASSERT_EQUALS(WordType(0), w.load()); w.store(1); ASSERT_EQUALS(WordType(1), w.load()); ASSERT_EQUALS(WordType(1), w.swap(2)); ASSERT_EQUALS(WordType(2), w.load()); ASSERT_EQUALS(WordType(2), w.compareAndSwap(0, 1)); ASSERT_EQUALS(WordType(2), w.load()); ASSERT_EQUALS(WordType(2), w.compareAndSwap(2, 1)); ASSERT_EQUALS(WordType(1), w.load()); ASSERT_EQUALS(WordType(1), w.fetchAndAdd(14)); ASSERT_EQUALS(WordType(17), w.addAndFetch(2)); ASSERT_EQUALS(WordType(16), w.subtractAndFetch(1)); ASSERT_EQUALS(WordType(16), w.fetchAndSubtract(1)); ASSERT_EQUALS(WordType(15), w.compareAndSwap(15, 0)); ASSERT_EQUALS(WordType(0), w.load()); } TEST(AtomicWordTests, BasicOperationsUnsigned32Bit) { typedef AtomicUInt32::WordType WordType; testAtomicWordBasicOperations(); AtomicUInt32 w(0xdeadbeef); ASSERT_EQUALS(WordType(0xdeadbeef), w.compareAndSwap(0, 1)); ASSERT_EQUALS(WordType(0xdeadbeef), w.compareAndSwap(0xdeadbeef, 0xcafe1234)); ASSERT_EQUALS(WordType(0xcafe1234), w.fetchAndAdd(0xf000)); ASSERT_EQUALS(WordType(0xcaff0234), w.swap(0)); ASSERT_EQUALS(WordType(0), w.load()); } TEST(AtomicWordTests, BasicOperationsUnsigned64Bit) { typedef AtomicUInt64::WordType WordType; testAtomicWordBasicOperations(); AtomicUInt64 w(0xdeadbeefcafe1234ULL); ASSERT_EQUALS(WordType(0xdeadbeefcafe1234ULL), w.compareAndSwap(0, 1)); ASSERT_EQUALS(WordType(0xdeadbeefcafe1234ULL), w.compareAndSwap(0xdeadbeefcafe1234ULL, 0xfedcba9876543210ULL)); ASSERT_EQUALS(WordType(0xfedcba9876543210ULL), w.fetchAndAdd(0xf0000000ULL)); ASSERT_EQUALS(WordType(0xfedcba9966543210ULL), w.swap(0)); ASSERT_EQUALS(WordType(0), w.load()); } TEST(AtomicWordTests, BasicOperationsSigned32Bit) { typedef AtomicInt32::WordType WordType; testAtomicWordBasicOperations(); AtomicInt32 w(0xdeadbeef); ASSERT_EQUALS(WordType(0xdeadbeef), w.compareAndSwap(0, 1)); ASSERT_EQUALS(WordType(0xdeadbeef), w.compareAndSwap(0xdeadbeef, 0xcafe1234)); ASSERT_EQUALS(WordType(0xcafe1234), w.fetchAndAdd(0xf000)); ASSERT_EQUALS(WordType(0xcaff0234), w.swap(0)); ASSERT_EQUALS(WordType(0), w.load()); } TEST(AtomicWordTests, BasicOperationsSigned64Bit) { typedef AtomicInt64::WordType WordType; testAtomicWordBasicOperations(); AtomicInt64 w(0xdeadbeefcafe1234ULL); ASSERT_EQUALS(WordType(0xdeadbeefcafe1234LL), w.compareAndSwap(0, 1)); ASSERT_EQUALS(WordType(0xdeadbeefcafe1234LL), w.compareAndSwap(0xdeadbeefcafe1234LL, 0xfedcba9876543210LL)); ASSERT_EQUALS(WordType(0xfedcba9876543210LL), w.fetchAndAdd(0xf0000000LL)); ASSERT_EQUALS(WordType(0xfedcba9966543210LL), w.swap(0)); ASSERT_EQUALS(WordType(0), w.load()); } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/basic.h000066400000000000000000000013221273231111400231420ustar00rootroot00000000000000// basic.h /* * Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #ifdef _WIN32 #include "windows_basic.h" #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/compiler.h000066400000000000000000000105351273231111400237010ustar00rootroot00000000000000/* * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once /** * Include "mongo/platform/compiler.h" to get compiler-targeted macro definitions and utilities. * * The following macros are provided in all compiler environments: * * * MONGO_COMPILER_NORETURN * * Instructs the compiler that the decorated function will not return through the normal return * path. * * Correct: MONGO_COMPILER_NORETURN void myAbortFunction(); * * * MONGO_COMPILER_VARIABLE_UNUSED * * Instructs the compiler not to warn if it detects no use of the decorated variable. * Typically only useful for variables that are always declared but only used in * conditionally-compiled code. * * Correct: MONGO_COMPILER_VARIABLE_UNUSED int ignored; * * * MONGO_COMPILER_ALIGN_TYPE(ALIGNMENT) * * Instructs the compiler to use the given minimum alignment for the decorated type. * * Alignments should probably always be powers of two. Also, note that most allocators will not * be able to guarantee better than 16- or 32-byte alignment. * * Correct: * class MONGO_COMPILER_ALIGN_TYPE(16) MyClass {...}; * * Incorrect: * MONGO_COMPILER_ALIGN_TYPE(16) class MyClass {...}; * class MyClass{...} MONGO_COMPILER_ALIGN_TYPE(16); * * * MONGO_COMPILER_ALIGN_VARIABLE(ALIGNMENT) * * Instructs the compiler to use the given minimum alignment for the decorated variable. * * Note that most allocators will not allow heap allocated alignments that are better than 16- or * 32-byte aligned. Stack allocators may only guarantee up to the natural word length worth of * alignment. * * Correct: * class MyClass { * MONGO_COMPILER_ALIGN_VARIABLE(8) char a; * }; * * MONGO_COMPILER_ALIGN_VARIABLE(8) class MyClass {...} singletonInstance; * * Incorrect: * int MONGO_COMPILER_ALIGN_VARIABLE(16) a, b; * * * MONGO_COMPILER_API_EXPORT * * Instructs the compiler to label the given type, variable or function as part of the * exported interface of the library object under construction. * * Correct: * MONGO_COMPILER_API_EXPORT int globalSwitch; * class MONGO_COMPILER_API_EXPORT ExportedType { ... }; * MONGO_COMPILER_API_EXPORT SomeType exportedFunction(...); * * NOTE: Rather than using this macro directly, one typically declares another macro named for the * library, which is conditionally defined to either MONGO_COMIPLER_API_EXPORT or * MONGO_COMPILER_API_IMPORT based on whether the compiler is currently building the library or * building an object that depends on the library, respectively. For example, MONGO_CLIENT_API * might be defined to MONGO_COMPILER_API_EXPORT when building the MongoDB shared library, and to * MONGO_COMPILER_API_IMPORT when building an application that links against the shared library. * * * MONGO_COMPILER_API_IMPORT * * Instructs the compiler to label the given type, variable or function as imported * from another library, and not part of the library object under construction. * * Same correct/incorrect usage as for MONGO_COMPILER_API_EXPORT. * * * MONGO_COMPILER_API_CALLING_CONVENTION * * Explicitly decorates a function declaration the api calling convention used for * shared libraries. * * Same correct/incorrect usage as for MONGO_COMPILER_API_EXPORT. * * MONGO_COMPILER_API_DEPRECATED(MSG) * * Designates a function declaration as deprecated, causing the compiler to emit a warning * if it is invoked. * * Example: * MONGO_COMPILER_API_DEPRECATED("Deprecated in MongoDB 2.8") Ret& deprecatedMethod(); * */ #if defined(_MSC_VER) #include "mongo/platform/compiler_msvc.h" #elif defined(__GNUC__) #include "mongo/platform/compiler_gcc.h" #else #error "Unsupported compiler family" #endif #define MONGO_CLIENT_DEPRECATED(MSG) MONGO_COMPILER_API_DEPRECATED(MSG) mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/compiler_gcc.h000066400000000000000000000062361273231111400245200ustar00rootroot00000000000000/* * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * // TODO: consider splitting out clang specific functionality * Compiler-specific implementations for gcc (and clang). * * Refer to mongo/platform/compiler.h for usage documentation. */ #pragma once #define MONGO_COMPILER_NORETURN __attribute__((__noreturn__)) #define MONGO_COMPILER_VARIABLE_UNUSED __attribute__((__unused__)) #define MONGO_COMPILER_ALIGN_TYPE(ALIGNMENT) __attribute__((__aligned__(ALIGNMENT))) #define MONGO_COMPILER_ALIGN_VARIABLE(ALIGNMENT) __attribute__((__aligned__(ALIGNMENT))) // NOTE(schwerin): These visibility and calling-convention macro definitions assume we're not using // GCC/CLANG to target native Windows. If/when we decide to do such targeting, we'll need to change // compiler flags on Windows to make sure we use an appropriate calling convention, and configure // MONGO_COMPILER_API_EXPORT, MONGO_COMPILER_API_IMPORT and MONGO_COMPILER_API_CALLING_CONVENTION // correctly. I believe "correctly" is the following: // // #ifdef _WIN32 // #define MONGO_COMIPLER_API_EXPORT __attribute__(( __dllexport__ )) // #define MONGO_COMPILER_API_IMPORT __attribute__(( __dllimport__ )) // #ifdef _M_IX86 // #define MONGO_COMPILER_API_CALLING_CONVENTION __attribute__((__cdecl__)) // #else // #define MONGO_COMPILER_API_CALLING_CONVENTION // #endif // #else ... fall through to the definitions below. #define MONGO_COMPILER_API_EXPORT __attribute__((__visibility__("default"))) #define MONGO_COMPILER_API_IMPORT #define MONGO_COMPILER_API_CALLING_CONVENTION // old versions of gcc and clang don't accept a message #ifdef __clang__ // for compatibility with older versions of clang #ifndef __has_extension #define __has_extension __has_feature #endif // Technically __attribute__(deprecated) is supposed to come at the end of the declaration, but // GCC and clang accept it at the start, which eases compatibility with MSVC #if __has_extension(attribute_deprecated_with_message) #define MONGO_COMPILER_API_DEPRECATED(MSG) __attribute__((deprecated(MSG))) #else // older clang doesn't support message #define MONGO_COMPILER_API_DEPRECATED(MSG) __attribute__((deprecated)) #endif #else // we are using GCC #if __GNUC__ > 4 || ((__GNUC__ == 4) && __GNUC_MINOR > 5) // deprecation messages were added in 4.5 #define MONGO_COMPILER_API_DEPRECATED(MSG) __attribute__((deprecated(MSG))) #else // Older GCC doesn't support message #define MONGO_COMPILER_API_DEPRECATED(MSG) __attribute__((deprecated)) #endif #endif #define MONGO_likely(x) static_cast(__builtin_expect(static_cast(x), 1)) #define MONGO_unlikely(x) static_cast(__builtin_expect(static_cast(x), 0)) mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/compiler_msvc.h000066400000000000000000000030631273231111400247270ustar00rootroot00000000000000/* * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Compiler-specific implementations for MSVC. * * Refer to mongo/platform/compiler.h for usage documentation. */ #pragma once #define MONGO_COMPILER_NORETURN __declspec(noreturn) #define MONGO_COMPILER_VARIABLE_UNUSED #define MONGO_COMPILER_ALIGN_TYPE(ALIGNMENT) __declspec(align(ALIGNMENT)) #define MONGO_COMPILER_ALIGN_VARIABLE(ALIGNMENT) __declspec(align(ALIGNMENT)) #define MONGO_COMPILER_API_EXPORT __declspec(dllexport) #define MONGO_COMPILER_API_IMPORT __declspec(dllimport) #ifdef _M_IX86 // 32-bit x86 supports multiple of calling conventions. We build supporting the cdecl convention // (most common). By labeling our exported and imported functions as such, we do a small favor to // 32-bit Windows developers. #define MONGO_COMPILER_API_CALLING_CONVENTION __cdecl #else #define MONGO_COMPILER_API_CALLING_CONVENTION #endif #define MONGO_COMPILER_API_DEPRECATED(MSG) __declspec(deprecated(MSG)) #define MONGO_likely(x) bool(x) #define MONGO_unlikely(x) bool(x) mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/cstdint.h000066400000000000000000000025561273231111400235430ustar00rootroot00000000000000/* * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once /** * Include "mongo/platform/cstdint.h" to get the C++11 cstdint types in namespace mongo. */ #if defined(_MSC_VER) #include #define _MONGO_STDINT_NAMESPACE std #elif defined(__GNUC__) #include #define _MONGO_STDINT_NAMESPACE #else #error "Unsupported compiler family" #endif namespace mongo { using _MONGO_STDINT_NAMESPACE::int8_t; using _MONGO_STDINT_NAMESPACE::int16_t; using _MONGO_STDINT_NAMESPACE::int32_t; using _MONGO_STDINT_NAMESPACE::int64_t; using _MONGO_STDINT_NAMESPACE::intptr_t; using _MONGO_STDINT_NAMESPACE::uint8_t; using _MONGO_STDINT_NAMESPACE::uint16_t; using _MONGO_STDINT_NAMESPACE::uint32_t; using _MONGO_STDINT_NAMESPACE::uint64_t; using _MONGO_STDINT_NAMESPACE::uintptr_t; } // namespace mongo #undef _MONGO_STDINT_NAMESPACE mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/endian.h000066400000000000000000000301211273231111400233160ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #include #include #include #include #include #include "mongo/platform/cstdint.h" #pragma push_macro("MONGO_UINT16_SWAB") #pragma push_macro("MONGO_UINT32_SWAB") #pragma push_macro("MONGO_UINT64_SWAB") #pragma push_macro("MONGO_LITTLE_ENDIAN") #pragma push_macro("MONGO_BIG_ENDIAN") #pragma push_macro("htobe16") #pragma push_macro("htobe32") #pragma push_macro("htobe64") #pragma push_macro("htole16") #pragma push_macro("htole32") #pragma push_macro("htole64") #pragma push_macro("be16toh") #pragma push_macro("be32toh") #pragma push_macro("be64toh") #pragma push_macro("le16toh") #pragma push_macro("le32toh") #pragma push_macro("le64toh") #undef MONGO_UINT16_SWAB #undef MONGO_UINT32_SWAB #undef MONGO_UINT64_SWAB #undef MONGO_LITTLE_ENDIAN #undef MONGO_BIG_ENDIAN #undef htobe16 #undef htobe32 #undef htobe64 #undef htole16 #undef htole32 #undef htole64 #undef be16toh #undef be32toh #undef be64toh #undef le16toh #undef le32toh #undef le64toh #define MONGO_LITTLE_ENDIAN 1234 #define MONGO_BIG_ENDIAN 4321 #if defined(_MSC_VER) && (_MSC_VER >= 1300) #include #define MONGO_UINT16_SWAB(v) _byteswap_ushort(v) #define MONGO_UINT32_SWAB(v) _byteswap_ulong(v) #define MONGO_UINT64_SWAB(v) _byteswap_uint64(v) #elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \ (__clang_major__ >= 3) && (__clang_minor__ >= 1) #if __has_builtin(__builtin_bswap16) #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v) #endif #if __has_builtin(__builtin_bswap32) #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v) #endif #if __has_builtin(__builtin_bswap64) #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v) #endif #elif defined(__GNUC__) && (__GNUC__ >= 4) #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3 #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v) #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v) #endif #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8 #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v) #endif #elif defined(__sun) #include #define MONGO_UINT16_SWAB(v) BSWAP_16(v) #define MONGO_UINT32_SWAB(v) BSWAP_32(v) #define MONGO_UINT64_SWAB(v) BSWAP_64(v) #endif #ifndef MONGO_UINT16_SWAB #define MONGO_UINT16_SWAB(v) endian::bswap_slow16(v) #endif #ifndef MONGO_UINT32_SWAB #define MONGO_UINT32_SWAB(v) endian::bswap_slow32(v) #endif #ifndef MONGO_UINT64_SWAB #define MONGO_UINT64_SWAB(v) endian::bswap_slow64(v) #endif #if MONGO_BYTE_ORDER == MONGO_LITTLE_ENDIAN #define htobe16(v) MONGO_UINT16_SWAB(v) #define htobe32(v) MONGO_UINT32_SWAB(v) #define htobe64(v) MONGO_UINT64_SWAB(v) #define htole16(v) (v) #define htole32(v) (v) #define htole64(v) (v) #define be16toh(v) MONGO_UINT16_SWAB(v) #define be32toh(v) MONGO_UINT32_SWAB(v) #define be64toh(v) MONGO_UINT64_SWAB(v) #define le16toh(v) (v) #define le32toh(v) (v) #define le64toh(v) (v) #elif MONGO_BYTE_ORDER == MONGO_BIG_ENDIAN #define htobe16(v) (v) #define htobe32(v) (v) #define htobe64(v) (v) #define htole16(v) MONGO_UINT16_SWAB(v) #define htole32(v) MONGO_UINT32_SWAB(v) #define htole64(v) MONGO_UINT64_SWAB(v) #define be16toh(v) (v) #define be32toh(v) (v) #define be64toh(v) (v) #define le16toh(v) MONGO_UINT16_SWAB(v) #define le32toh(v) MONGO_UINT32_SWAB(v) #define le64toh(v) MONGO_UINT64_SWAB(v) #else #error \ "The endianness of target architecture is unknown. " \ "Please define MONGO_BYTE_ORDER" #endif namespace mongo { namespace endian { static inline uint16_t bswap_slow16(uint16_t v) { return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); } static inline uint32_t bswap_slow32(uint32_t v) { return ((v & 0x000000FFUL) << 24) | ((v & 0x0000FF00UL) << 8) | ((v & 0x00FF0000UL) >> 8) | ((v & 0xFF000000UL) >> 24); } static inline uint64_t bswap_slow64(uint64_t v) { return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); } template struct ByteOrderConverter; template <> struct ByteOrderConverter { typedef uint8_t T; inline static T nativeToBig(T t) { return t; } inline static T bigToNative(T t) { return t; } inline static T nativeToLittle(T t) { return t; } inline static T littleToNative(T t) { return t; } }; template <> struct ByteOrderConverter { typedef uint16_t T; inline static T nativeToBig(T t) { return htobe16(t); } inline static T bigToNative(T t) { return be16toh(t); } inline static T nativeToLittle(T t) { return htole16(t); } inline static T littleToNative(T t) { return le16toh(t); } }; template <> struct ByteOrderConverter { typedef uint32_t T; inline static T nativeToBig(T t) { return htobe32(t); } inline static T bigToNative(T t) { return be32toh(t); } inline static T nativeToLittle(T t) { return htole32(t); } inline static T littleToNative(T t) { return le32toh(t); } }; template <> struct ByteOrderConverter { typedef uint64_t T; inline static T nativeToBig(T t) { return htobe64(t); } inline static T bigToNative(T t) { return be64toh(t); } inline static T nativeToLittle(T t) { return htole64(t); } inline static T littleToNative(T t) { return le64toh(t); } }; template <> struct ByteOrderConverter { typedef int8_t T; inline static T nativeToBig(T t) { return t; } inline static T bigToNative(T t) { return t; } inline static T nativeToLittle(T t) { return t; } inline static T littleToNative(T t) { return t; } }; template <> struct ByteOrderConverter { typedef int16_t T; inline static T nativeToBig(T t) { return htobe16(static_cast(t)); } inline static T bigToNative(T t) { return be16toh(static_cast(t)); } inline static T nativeToLittle(T t) { return htole16(static_cast(t)); } inline static T littleToNative(T t) { return le16toh(static_cast(t)); } }; template <> struct ByteOrderConverter { typedef int32_t T; inline static T nativeToBig(T t) { return htobe32(static_cast(t)); } inline static T bigToNative(T t) { return be32toh(static_cast(t)); } inline static T nativeToLittle(T t) { return htole32(static_cast(t)); } inline static T littleToNative(T t) { return le32toh(static_cast(t)); } }; template <> struct ByteOrderConverter { typedef int64_t T; inline static T nativeToBig(T t) { return htobe64(static_cast(t)); } inline static T bigToNative(T t) { return be64toh(static_cast(t)); } inline static T nativeToLittle(T t) { return htole64(static_cast(t)); } inline static T littleToNative(T t) { return le64toh(static_cast(t)); } }; template <> struct ByteOrderConverter { typedef float T; inline static T nativeToBig(T t) { BOOST_STATIC_ASSERT(sizeof(T) == sizeof(uint32_t)); uint32_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = htobe32(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T bigToNative(T t) { uint32_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = be32toh(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T nativeToLittle(T t) { uint32_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = htole32(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T littleToNative(T t) { uint32_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = le32toh(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } }; template <> struct ByteOrderConverter { typedef double T; inline static T nativeToBig(T t) { BOOST_STATIC_ASSERT(sizeof(T) == sizeof(uint64_t)); uint64_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = htobe64(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T bigToNative(T t) { uint64_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = be64toh(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T nativeToLittle(T t) { uint64_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = htole64(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } inline static T littleToNative(T t) { uint64_t temp; std::memcpy(&temp, &t, sizeof(t)); temp = le64toh(temp); std::memcpy(&t, &temp, sizeof(t)); return t; } }; // Use a typemape to normalize non-fixed-width integral types to the associated fixed width // types. template struct IntegralTypeMap { typedef T type; }; template <> struct IntegralTypeMap { BOOST_STATIC_ASSERT(CHAR_BIT == 8); typedef int8_t type; }; template <> struct IntegralTypeMap { BOOST_STATIC_ASSERT(CHAR_BIT == 8); typedef uint8_t type; }; template <> struct IntegralTypeMap { BOOST_STATIC_ASSERT(CHAR_BIT == 8); typedef boost::mpl::if_c::value, int8_t, uint8_t>::type type; }; template <> struct IntegralTypeMap { BOOST_STATIC_ASSERT(sizeof(long long) == sizeof(int64_t)); typedef int64_t type; }; template <> struct IntegralTypeMap { BOOST_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); typedef uint64_t type; }; template inline T nativeToBig(T t) { return ByteOrderConverter::type>::nativeToBig(t); } template inline T bigToNative(T t) { return ByteOrderConverter::type>::bigToNative(t); } template inline T nativeToLittle(T t) { return ByteOrderConverter::type>::nativeToLittle(t); } template inline T littleToNative(T t) { return ByteOrderConverter::type>::littleToNative(t); } } // namespace endian } // namespace mongo #undef MONGO_UINT16_SWAB #undef MONGO_UINT32_SWAB #undef MONGO_UINT64_SWAB #undef MONGO_LITTLE_ENDIAN #undef MONGO_BIG_ENDIAN #undef htobe16 #undef htobe32 #undef htobe64 #undef htole16 #undef htole32 #undef htole64 #undef be16toh #undef be32toh #undef be64toh #undef le16toh #undef le32toh #undef le64toh #pragma pop_macro("MONGO_UINT16_SWAB") #pragma pop_macro("MONGO_UINT32_SWAB") #pragma pop_macro("MONGO_UINT64_SWAB") #pragma pop_macro("MONGO_LITTLE_ENDIAN") #pragma pop_macro("MONGO_BIG_ENDIAN") #pragma pop_macro("htobe16") #pragma pop_macro("htobe32") #pragma pop_macro("htobe64") #pragma pop_macro("htole16") #pragma pop_macro("htole32") #pragma pop_macro("htole64") #pragma pop_macro("be16toh") #pragma pop_macro("be32toh") #pragma pop_macro("be64toh") #pragma pop_macro("le16toh") #pragma pop_macro("le32toh") #pragma pop_macro("le64toh") mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/endian_test.cpp000066400000000000000000000343131273231111400247170ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/endian.h" #include #include "mongo/unittest/unittest.h" namespace mongo { using namespace endian; TEST(EndianTest, TestSlow16) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; uint16_t le; uint16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); ASSERT_EQUALS(be, endian::bswap_slow16(le)); ASSERT_EQUALS(le, endian::bswap_slow16(be)); } TEST(EndianTest, TestSlow32) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; uint32_t le; uint32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); ASSERT_EQUALS(be, endian::bswap_slow32(le)); ASSERT_EQUALS(le, endian::bswap_slow32(be)); } TEST(EndianTest, TestSlow64) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint64_t le; uint64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); ASSERT_EQUALS(be, endian::bswap_slow64(le)); ASSERT_EQUALS(le, endian::bswap_slow64(be)); } TEST(EndianTest, NativeToBig_uint16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; uint16_t le; uint16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_uint32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; uint32_t le; uint32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_uint64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint64_t le; uint64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_int16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; int16_t le; int16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_int32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; int32_t le; int32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_int64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; int64_t le; int64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_float) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; float le; float be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToBig_double) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; double le; double be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(be, nativeToBig(le)); #else ASSERT_EQUALS(be, nativeToBig(be)); #endif } TEST(EndianTest, NativeToLittle_uint16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; uint16_t le; uint16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_uint32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; uint32_t le; uint32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_uint64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint64_t le; uint64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_int16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; int16_t le; int16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_int32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; int32_t le; int32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_int64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; int64_t le; int64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_float) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; float le; float be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, NativeToLittle_double) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; double le; double be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, nativeToLittle(le)); #else ASSERT_EQUALS(le, nativeToLittle(be)); #endif } TEST(EndianTest, LittleToNative_uint16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; uint16_t le; uint16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_uint32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; uint32_t le; uint32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_uint64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint64_t le; uint64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_int16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; int16_t le; int16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_int32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; int32_t le; int32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_int64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; int64_t le; int64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_float) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; float le; float be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, LittleToNative_double) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; double le; double be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, littleToNative(le)); #else ASSERT_EQUALS(be, littleToNative(le)); #endif } TEST(EndianTest, BigToNative_uint16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; uint16_t le; uint16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_uint32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; uint32_t le; uint32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_uint64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint64_t le; uint64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_int16_t) { uint8_t le_buf[] = {0x01, 0x02}; uint8_t be_buf[] = {0x02, 0x01}; int16_t le; int16_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_int32_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; int32_t le; int32_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_int64_t) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; int64_t le; int64_t be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_float) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04}; uint8_t be_buf[] = {0x04, 0x03, 0x02, 0x01}; float le; float be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } TEST(EndianTest, BigToNative_double) { uint8_t le_buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t be_buf[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; double le; double be; std::memcpy(&le, le_buf, sizeof(le)); std::memcpy(&be, be_buf, sizeof(be)); #if MONGO_BYTE_ORDER == 1234 ASSERT_EQUALS(le, bigToNative(be)); #else ASSERT_EQUALS(be, bigToNative(be)); #endif } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/float_utils.h000066400000000000000000000017331273231111400244140ustar00rootroot00000000000000/* * Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { inline bool isNaN(double d) { return d != d; } inline bool isInf(double d, int* sign = 0) { volatile double tmp = d; if ((tmp == d) && ((tmp - d) != 0.0)) { if (sign) { *sign = (d < 0.0 ? -1 : 1); } return true; } if (sign) { *sign = 0; } return false; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/hash_namespace.h000066400000000000000000000043051273231111400250240ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once // We need to drag in a C++ header so we can examine __GXX_EXPERIMENTAL_CXX0X__ or // _LIBCPP_VERSION meaningfully. The header is pretty lightweight, mostly unavoidable, // and almost certain to bring in the standard library configuration macros. #include // NOTE(acm): Before gcc-4.7, __cplusplus is always defined to be 1, so we can't reliably // detect C++11 support by exclusively checking the value of __cplusplus. Additionaly, libc++, // whether in C++11 or C++03 mode, doesn't use TR1 and drops things into std instead. #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(_LIBCPP_VERSION) #include #define MONGO_HASH_NAMESPACE_START namespace std { #define MONGO_HASH_NAMESPACE_END } #define MONGO_HASH_NAMESPACE std #elif defined(_MSC_VER) && _MSC_VER >= 1500 #if _MSC_VER >= 1600 /* Visual Studio 2010+ */ #include #define MONGO_HASH_NAMESPACE_START namespace std { #define MONGO_HASH_NAMESPACE_END } #define MONGO_HASH_NAMESPACE std #else /* Older Visual Studio */ #include #define MONGO_HASH_NAMESPACE_START \ namespace std { \ namespace tr1 { #define MONGO_HASH_NAMESPACE_END \ } \ } #define MONGO_HASH_NAMESPACE std::tr1 #endif #elif defined(__GNUC__) #include #define MONGO_HASH_NAMESPACE_START \ namespace std { \ namespace tr1 { #define MONGO_HASH_NAMESPACE_END \ } \ } #define MONGO_HASH_NAMESPACE std::tr1 #else #error "Cannot determine namespace for 'hash'" #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/random.cpp000066400000000000000000000071401273231111400237000ustar00rootroot00000000000000// random.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/platform/basic.h" #include "mongo/platform/random.h" #include #ifndef _WIN32 #include #endif #define _CRT_RAND_S #include #include #include #include namespace mongo { // ---- PseudoRandom ----- uint32_t PseudoRandom::nextUInt32() { uint32_t t = _x ^ (_x << 11); _x = _y; _y = _z; _z = _w; return _w = _w ^ (_w >> 19) ^ (t ^ (t >> 8)); } namespace { const uint32_t default_y = 362436069; const uint32_t default_z = 521288629; const uint32_t default_w = 88675123; } // namespace void PseudoRandom::_init(uint32_t seed) { _x = seed; _y = default_y; _z = default_z; _w = default_w; } PseudoRandom::PseudoRandom(uint32_t seed) { _init(seed); } PseudoRandom::PseudoRandom(int32_t seed) { _init(static_cast(seed)); } PseudoRandom::PseudoRandom(int64_t seed) { _init(static_cast(seed >> 32) ^ static_cast(seed)); } int32_t PseudoRandom::nextInt32() { return nextUInt32(); } int64_t PseudoRandom::nextInt64() { uint64_t a = nextUInt32(); uint64_t b = nextUInt32(); return (a << 32) | b; } // --- SecureRandom ---- SecureRandom::~SecureRandom() {} #ifdef _WIN32 class WinSecureRandom : public SecureRandom { virtual ~WinSecureRandom() {} int64_t nextInt64() { uint32_t a, b; if (rand_s(&a)) { abort(); } if (rand_s(&b)) { abort(); } return (static_cast(a) << 32) | b; } }; SecureRandom* SecureRandom::create() { return new WinSecureRandom(); } #elif defined(__linux__) || defined(__sunos__) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || defined(__gnu_hurd__) class InputStreamSecureRandom : public SecureRandom { public: InputStreamSecureRandom(const char* fn) { _in = new std::ifstream(fn, std::ios::binary | std::ios::in); if (!_in->is_open()) { error() << "cannot open " << fn << " " << strerror(errno); fassertFailed(28839); } } ~InputStreamSecureRandom() { delete _in; } int64_t nextInt64() { int64_t r; _in->read(reinterpret_cast(&r), sizeof(r)); if (_in->fail()) { error() << "InputStreamSecureRandom failed to generate random bytes"; fassertFailed(28840); } return r; } private: std::ifstream* _in; }; SecureRandom* SecureRandom::create() { return new InputStreamSecureRandom("/dev/urandom"); } #elif defined(__openbsd__) class Arc4SecureRandom : public SecureRandom { public: int64_t nextInt64() { int64_t value; arc4random_buf(&value, sizeof(value)); return value; } }; SecureRandom* SecureRandom::create() { return new Arc4SecureRandom(); } #else #error Must implement SecureRandom for platform #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/random.h000066400000000000000000000041111273231111400233400ustar00rootroot00000000000000// random.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/platform/cstdint.h" namespace mongo { /** * Uses http://en.wikipedia.org/wiki/Xorshift */ class PseudoRandom { public: PseudoRandom(int32_t seed); PseudoRandom(uint32_t seed); PseudoRandom(int64_t seed); int32_t nextInt32(); int64_t nextInt64(); /** * @return a number between 0 and max */ int32_t nextInt32(int32_t max) { return static_cast(nextInt32()) % static_cast(max); } /** * @return a number between 0 and max */ int64_t nextInt64(int64_t max) { return static_cast(nextInt64()) % static_cast(max); } /** * @return a number between 0 and max * * This makes PseudoRandom instances passable as the third argument to std::random_shuffle */ intptr_t operator()(intptr_t max) { if (sizeof(intptr_t) == 4) return static_cast(nextInt32(static_cast(max))); return static_cast(nextInt64(static_cast(max))); } private: void _init(uint32_t seed); uint32_t nextUInt32(); uint32_t _x; uint32_t _y; uint32_t _z; uint32_t _w; }; /** * More secure random numbers * Suitable for nonce/crypto * Slower than PseudoRandom, so only use when really need */ class SecureRandom { public: virtual ~SecureRandom(); virtual int64_t nextInt64() = 0; static SecureRandom* create(); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/random_test.cpp000066400000000000000000000102331273231111400247340ustar00rootroot00000000000000// random_test.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "mongo/platform/random.h" #include "mongo/unittest/unittest.h" namespace mongo { TEST(RandomTest, Seed1) { PseudoRandom a(12); PseudoRandom b(12); for (int i = 0; i < 100; i++) { ASSERT_EQUALS(a.nextInt32(), b.nextInt32()); } } TEST(RandomTest, Seed2) { PseudoRandom a(12); PseudoRandom b(12); for (int i = 0; i < 100; i++) { ASSERT_EQUALS(a.nextInt64(), b.nextInt64()); } } TEST(RandomTest, Seed3) { PseudoRandom a(11); PseudoRandom b(12); ASSERT_NOT_EQUALS(a.nextInt32(), b.nextInt32()); } TEST(RandomTest, Seed4) { PseudoRandom a(11); std::set s; for (int i = 0; i < 100; i++) { s.insert(a.nextInt32()); } ASSERT_EQUALS(100U, s.size()); } TEST(RandomTest, Seed5) { const int64_t seed = 0xCC453456FA345FABLL; PseudoRandom a(seed); std::set s; for (int i = 0; i < 100; i++) { s.insert(a.nextInt32()); } ASSERT_EQUALS(100U, s.size()); } TEST(RandomTest, R1) { PseudoRandom a(11); std::set s; for (int i = 0; i < 100; i++) { s.insert(a.nextInt32()); } ASSERT_EQUALS(100U, s.size()); } TEST(RandomTest, R2) { PseudoRandom a(11); std::set s; for (int i = 0; i < 100; i++) { s.insert(a.nextInt64()); } ASSERT_EQUALS(100U, s.size()); } TEST(RandomTest, NextInt32SanityCheck) { // Generate 1000 int32s and assert that each bit is set between 40% and 60% of the time. This is // a bare minimum sanity check, not an attempt to ensure quality random numbers. PseudoRandom a(11); std::vector nums; for (int i = 0; i < 1000; i++) { nums.push_back(a.nextInt32()); } for (int bit = 0; bit < 32; bit++) { int onesCount = 0; for (size_t i = 0; i != nums.size(); ++i) { int32_t num = nums[i]; bool isSet = (num >> bit) & 1; if (isSet) onesCount++; } if (onesCount < 400 || onesCount > 600) FAIL() << "bit " << bit << " was set " << (onesCount / 10.) << "% of the time."; } } TEST(RandomTest, NextInt64SanityCheck) { // Generate 1000 int64s and assert that each bit is set between 40% and 60% of the time. This is // a bare minimum sanity check, not an attempt to ensure quality random numbers. PseudoRandom a(11); std::vector nums; for (int i = 0; i < 1000; i++) { nums.push_back(a.nextInt64()); } for (int bit = 0; bit < 64; bit++) { int onesCount = 0; for (size_t i = 0; i != nums.size(); ++i) { int64_t num = nums[i]; bool isSet = (num >> bit) & 1; if (isSet) onesCount++; } if (onesCount < 400 || onesCount > 600) FAIL() << "bit " << bit << " was set " << (onesCount / 10.) << "% of the time."; } } TEST(RandomTest, NextInt32InRange) { PseudoRandom a(11); for (int i = 0; i < 1000; i++) { int32_t res = a.nextInt32(10); ASSERT_GE(res, 0); ASSERT_LT(res, 10); } } TEST(RandomTest, NextInt64InRange) { PseudoRandom a(11); for (int i = 0; i < 1000; i++) { int64_t res = a.nextInt64(10); ASSERT_GE(res, 0); ASSERT_LT(res, 10); } } TEST(RandomTest, Secure1) { SecureRandom* a = SecureRandom::create(); SecureRandom* b = SecureRandom::create(); for (int i = 0; i < 100; i++) { ASSERT_NOT_EQUALS(a->nextInt64(), b->nextInt64()); } delete a; delete b; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/strnlen.cpp000066400000000000000000000016171273231111400241100ustar00rootroot00000000000000/* Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/strnlen.h" #ifndef MONGO_HAVE_STRNLEN namespace mongo { size_t strnlen(const char* s, size_t maxlen) { for (size_t i = 0; i < maxlen; ++i) { if (s[i] == '\0') { return i; } } return maxlen; } } // namespace mongo #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/strnlen.h000066400000000000000000000014611273231111400235520ustar00rootroot00000000000000/* Copyright 2015 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include namespace mongo { #ifdef MONGO_HAVE_STRNLEN using ::strnlen; #else size_t strnlen(const char* s, size_t maxlen); #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/strtoll.h000066400000000000000000000016651273231111400235760ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #ifdef _WIN32 static inline long long strtoll(const char* nptr, char** endptr, int base) { return _strtoi64(nptr, endptr, base); } static inline unsigned long long strtoull(const char* nptr, char** endptr, int base) { return _strtoui64(nptr, endptr, base); } #endif // defined(_WIN32) mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/unordered_map.h000066400000000000000000000034411273231111400247110ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once // We need to drag in a C++ header so we can examine __GXX_EXPERIMENTAL_CXX0X__ or // _LIBCPP_VERSION meaningfully. The header is pretty lightweight, mostly unavoidable, // and almost certain to bring in the standard library configuration macros. #include // NOTE(acm): Before gcc-4.7, __cplusplus is always defined to be 1, so we can't reliably // detect C++11 support by exclusively checking the value of __cplusplus. Additionaly, libc++, // whether in C++11 or C++03 mode, doesn't use TR1 and drops things into std instead. #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(_LIBCPP_VERSION) #include namespace mongo { using std::unordered_map; } // namespace mongo #elif defined(_MSC_VER) && _MSC_VER >= 1500 #include namespace mongo { #if _MSC_VER >= 1600 /* Visual Studio 2010+ */ using std::unordered_map; #else using std::tr1::unordered_map; #endif } // namespace mongo #elif defined(__GNUC__) #include namespace mongo { using std::tr1::unordered_map; } // namespace mongo #else #error "Compiler's standard library does not provide a C++ unordered_map implementation." #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/unordered_set.h000066400000000000000000000034411273231111400247270ustar00rootroot00000000000000/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once // We need to drag in a C++ header so we can examine __GXX_EXPERIMENTAL_CXX0X__ or // _LIBCPP_VERSION meaningfully. The header is pretty lightweight, mostly unavoidable, // and almost certain to bring in the standard library configuration macros. #include // NOTE(acm): Before gcc-4.7, __cplusplus is always defined to be 1, so we can't reliably // detect C++11 support by exclusively checking the value of __cplusplus. Additionaly, libc++, // whether in C++11 or C++03 mode, doesn't use TR1 and drops things into std instead. #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(_LIBCPP_VERSION) #include namespace mongo { using std::unordered_set; } // namespace mongo #elif defined(_MSC_VER) && _MSC_VER >= 1500 #include namespace mongo { #if _MSC_VER >= 1600 /* Visual Studio 2010+ */ using std::unordered_set; #else using std::tr1::unordered_set; #endif } // namespace mongo #elif defined(__GNUC__) #include namespace mongo { using std::tr1::unordered_set; } // namespace mongo #else #error "Compiler's standard library does not provide a C++ unordered_set implementation." #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/platform/windows_basic.h000066400000000000000000000064541273231111400247270ustar00rootroot00000000000000// windows_basic.h /* * Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if !defined(_WIN32) #error "windows_basic included but _WIN32 is not defined" #endif // "If you define NTDDI_VERSION, you must also define _WIN32_WINNT": // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx #if defined(NTDDI_VERSION) && !defined(_WIN32_WINNT) #error NTDDI_VERSION defined but _WIN32_WINNT is undefined #endif // Ensure that _WIN32_WINNT is set to something before we include windows.h. For server builds // both _WIN32_WINNT and NTDDI_VERSION are set as defines on the command line, but we need // these here for things like client driver builds, where they may not already be set. #if !defined(_WIN32_WINNT) // Can't use symbolic versions here, since we may not have seen sdkddkver.h yet. #if defined(_WIN64) // 64-bit builds default to Windows Server 2003 support. #define _WIN32_WINNT 0x0502 #else // 32-bit builds default to Windows XP support. #define _WIN32_WINNT 0x0501 #endif #endif // As above, but for NTDDI_VERSION. Otherwise, would set our NTDDI_VERSION based on // _WIN32_WINNT, but not select the service pack revision. #if !defined(NTDDI_VERSION) // Can't use symbolic versions here, since we may not have seen sdkddkver.h yet. #if defined(_WIN64) // 64-bit builds default to Windows Server 2003 SP 2 support. #define NTDDI_VERSION 0x05020200 #else // 32-bit builds default to Windows XP SP 3 support. #define NTDDI_VERSION 0x05010300 #endif #endif // No need to set WINVER, SdkDdkVer.h does that for us, we double check this below. // for rand_s() usage: #define _CRT_RAND_S // Do not complain that about standard library functions that Windows believes should have // underscores in front of them, such as unlink(). #define _CRT_NONSTDC_NO_DEPRECATE // tell windows.h not to include a bunch of headers we don't need: #define WIN32_LEAN_AND_MEAN #include //this must be included before the first windows.h include #include #include #include // Should come either from the command line, or if not set there, the inclusion of sdkddkver.h // via windows.h above should set it based in _WIN32_WINNT, which is assuredly set by now. #if !defined(NTDDI_VERSION) #error "NTDDI_VERSION is not defined" #endif #if !defined(WINVER) || (WINVER != _WIN32_WINNT) #error "Expected WINVER to have been defined and to equal _WIN32_WINNT" #endif #if defined(_WIN64) #if !defined(NTDDI_WS03SP2) || (NTDDI_VERSION < NTDDI_WS03SP2) #error "64 bit mongo does not support Windows versions older than Windows Server 2003 SP 2" #endif #else #if !defined(NTDDI_WINXPSP3) || (NTDDI_VERSION < NTDDI_WINXPSP3) #error "32 bit mongo does not support Windows versions older than XP Service Pack 3" #endif #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/stdx/000077500000000000000000000000001273231111400210505ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/stdx/functional.h000066400000000000000000000024661273231111400233730ustar00rootroot00000000000000/** * Copyright (C) 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if __cplusplus >= 201103L #include namespace mongo { namespace stdx { using ::std::bind; using ::std::function; namespace placeholders = ::std::placeholders; } // namespace stdx } // namespace mongo #else #include #include namespace mongo { namespace stdx { using boost::bind; using boost::function; namespace placeholders { static boost::arg<1> _1; static boost::arg<2> _2; static boost::arg<3> _3; static boost::arg<4> _4; static boost::arg<5> _5; static boost::arg<6> _6; static boost::arg<7> _7; static boost::arg<8> _8; static boost::arg<9> _9; } // namespace placeholders } // namespace stdx } // namespace mongo #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/000077500000000000000000000000001273231111400217455ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/connection_string_test.cpp000066400000000000000000000052441273231111400272420ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest.h" #include #include "mongo/client/dbclientinterface.h" namespace mongo { using namespace std; /* Connection String */ TEST(ConnectionString, SameLogicalEndpoint) { string err1; string err2; ConnectionString cs1; ConnectionString cs2; // INVALID -- default non parsed state ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); cs2 = ConnectionString::parse("mongodb://host1,host2,host3", err1); ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); // MASTER cs1 = ConnectionString::parse("mongodb://localhost:1234", err1); cs2 = ConnectionString::parse("mongodb://localhost:1234", err2); ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); // PAIR -- compares the host + port even in swapped order cs1 = cs1.parse("mongodb://localhost:1234,localhost:5678", err1); cs2 = cs2.parse("mongodb://localhost:1234,localhost:5678", err2); ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); cs2 = cs2.parse("mongodb://localhost:5678,localhost:1234", err2); ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); // SET -- compares the set name only cs1 = cs1.parse("mongodb://localhost:1234,localhost:5678/?replicaSet=testset", err1); cs2 = cs2.parse("mongodb://localhost:5678,localhost:1234/?replicaSet=testset", err2); ASSERT_TRUE(cs1.sameLogicalEndpoint(cs2)); // Different parsing methods cs1 = cs1.parseDeprecated("testset/localhost:1234,localhost:5678", err1); cs2 = cs2.parse("mongodb://localhost:5678,localhost:1234", err2); ASSERT_FALSE(cs1.sameLogicalEndpoint(cs2)); } TEST(ConnectionString, TypeToString) { ASSERT_EQUALS(ConnectionString::typeToString(ConnectionString::INVALID), "invalid"); ASSERT_EQUALS(ConnectionString::typeToString(ConnectionString::MASTER), "master"); ASSERT_EQUALS(ConnectionString::typeToString(ConnectionString::PAIR), "pair"); ASSERT_EQUALS(ConnectionString::typeToString(ConnectionString::SET), "set"); ASSERT_EQUALS(ConnectionString::typeToString(ConnectionString::CUSTOM), "custom"); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/query_test.cpp000066400000000000000000000126621273231111400246640ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest.h" #include "mongo/client/dbclientinterface.h" namespace mongo { using namespace std; /* Query Class */ TEST(QueryTest, Explain) { Query q; q.explain(); ASSERT_TRUE(q.isComplex()); ASSERT_TRUE(q.isExplain()); } TEST(QueryTest, Snapshot) { Query q; q.snapshot(); ASSERT_TRUE(q.isComplex()); ASSERT_TRUE(q.obj.hasField("$snapshot")); ASSERT_TRUE(q.obj.getBoolField("$snapshot")); } TEST(QueryTest, Sort) { Query q; q.sort(BSON("a" << 1)); ASSERT_TRUE(q.isComplex()); BSONObj sort = q.getSort(); ASSERT_TRUE(sort.hasField("a")); ASSERT_EQUALS(sort.getIntField("a"), 1); } TEST(QueryTest, Hint) { Query q; q.hint(BSON("a" << 1)); BSONElement hint = q.getHint(); ASSERT_TRUE(hint.Obj().hasField("a")); ASSERT_EQUALS(hint.Obj().getIntField("a"), 1); } TEST(QueryTest, MinKey) { Query q; BSONObj minobj; q.minKey(minobj); ASSERT_TRUE(q.isComplex()); ASSERT_TRUE(q.obj.hasField("$min")); ASSERT_EQUALS(q.obj["$min"].Obj(), minobj); } TEST(QueryTest, MaxKey) { Query q; BSONObj maxobj; q.maxKey(maxobj); ASSERT_TRUE(q.isComplex()); ASSERT_TRUE(q.obj.hasField("$max")); ASSERT_EQUALS(q.obj["$max"].Obj(), maxobj); } TEST(QueryTest, ReadPreferencePrimary) { Query q("{}"); q.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "primary"); ASSERT_FALSE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); } TEST(QueryTest, ReadPreferencePrimaryPreferred) { Query q("{}"); q.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "primaryPreferred"); ASSERT_FALSE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); } TEST(QueryTest, ReadPreferenceSecondary) { Query q("{}"); q.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "secondary"); ASSERT_FALSE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); } TEST(QueryTest, ReadPreferenceSecondaryPreferred) { Query q("{}"); q.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "secondaryPreferred"); ASSERT_FALSE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); } TEST(QueryTest, ReadPreferenceNearest) { Query q("{}"); q.readPref(mongo::ReadPreference_Nearest, BSONArray()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "nearest"); ASSERT_FALSE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); } TEST(QueryTest, ReadPreferenceTagSets) { Query q("{}"); BSONObj tag_set1 = BSON("datacenter" << "nyc"); BSONObj tag_set2 = BSON("awesome" << "yeah"); BSONObjBuilder bob; BSONArrayBuilder bab; bab.append(tag_set1); bab.append(tag_set2); q.readPref(mongo::ReadPreference_SecondaryOnly, bab.arr()); ASSERT_TRUE(q.obj.hasField(Query::ReadPrefField.name())); BSONElement read_pref_elem = q.obj[Query::ReadPrefField.name()]; ASSERT_TRUE(read_pref_elem.isABSONObj()); BSONObj read_pref_obj = read_pref_elem.Obj(); ASSERT_EQUALS(read_pref_obj[Query::ReadPrefModeField.name()].String(), "secondary"); ASSERT_TRUE(read_pref_obj.hasField(Query::ReadPrefTagsField.name())); vector tag_sets = read_pref_obj[Query::ReadPrefTagsField.name()].Array(); ASSERT_EQUALS(tag_sets[0].Obj(), tag_set1); ASSERT_EQUALS(tag_sets[1].Obj(), tag_set2); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/unit_test_main.cpp000066400000000000000000000017361273231111400255020ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "gtest/gtest.h" #include "mongo/client/init.h" int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); mongo::client::GlobalInstance instance; if (!instance.initialized()) { std::cerr << "failed to initialize the client driver: " << instance.status() << std::endl; ::abort(); } return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/unittest.h000066400000000000000000000044651273231111400240060ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Shim to allow mongoclient tests to build with gtest instead of * built in MongoDB unittest framework. * * Note: FAIL(str) has been converted to FAIL() << str; in tests. * */ #pragma once #include #include #include #include #define ASSERT ASSERT_TRUE #define ASSERT_EQUALS ASSERT_EQ #define ASSERT_NOT_EQUALS ASSERT_NE #define ASSERT_GREATER_THAN ASSERT_GT #define ASSERT_LESS_THAN_OR_EQUALS ASSERT_LE #define ASSERT_LESS_THAN ASSERT_LT #define ASSERT_GREATER_THAN_OR_EQUALS ASSERT_GE #define ASSERT_GREATER_THAN ASSERT_GT #define ASSERT_APPROX_EQUAL ASSERT_NEAR #define ASSERT_OK(EXPRESSION) ASSERT_EQUALS(::mongo::Status::OK(), (EXPRESSION)) #define ASSERT_NOT_OK(EXPRESSION) ASSERT_NOT_EQUALS(::mongo::Status::OK(), (EXPRESSION)) #define ASSERT_THROWS(STATEMENT, EXCEPTION) ASSERT_THROW(STATEMENT, EXCEPTION) namespace mongo { namespace unittest { class Test : public ::testing::Test { virtual void setUp() {} virtual void SetUp() { setUp(); } virtual void tearDown() {} virtual void TearDown() { tearDown(); } }; /** * Get the value out of a StatusWith, or throw an exception if it is not OK. */ template const T& assertGet(const StatusWith& swt) { if (!swt.getStatus().isOK()) ::abort(); return swt.getValue(); } } // unittest } // mongo using namespace mongo; using namespace mongoutils; #define DBTEST_SHIM_TEST_NAMED(klass, name, ...) \ TEST(klass, name) { \ klass(__VA_ARGS__).run(); \ } #define DBTEST_SHIM_TEST(klass, ...) DBTEST_SHIM_TEST_NAMED(klass, Test, __VA_ARGS__) mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/unittest_helpers.cpp000066400000000000000000000015701273231111400260550ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest_helpers.h" #include #include "mongo/util/time_support.h" namespace mongo { std::ostream& operator<<(std::ostream& s, const Date_t& t) { s << t.toString(); return s; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/unittest/unittest_helpers.h000066400000000000000000000014701273231111400255210ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include namespace mongo { struct Date_t; // So that you can ASSERT_EQUALS two Date_ts std::ostream& operator<<(std::ostream& s, const Date_t& t); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/000077500000000000000000000000001273231111400210435ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/util/assert_util.cpp000066400000000000000000000143461273231111400241150ustar00rootroot00000000000000// assert_util.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/platform/basic.h" #include "mongo/util/assert_util.h" using namespace std; #ifndef _WIN32 #include #include #endif #include "mongo/bson/bsonobjbuilder.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" namespace mongo { string DBException::toString() const { stringstream ss; ss << getCode() << " " << what(); return ss.str(); } ErrorCodes::Error DBException::convertExceptionCode(int exCode) { if (exCode == 0) return ErrorCodes::UnknownError; return static_cast(exCode); } void ExceptionInfo::append(BSONObjBuilder& b, const char* m, const char* c) const { if (msg.empty()) b.append(m, "unknown assertion"); else b.append(m, msg); if (code) b.append(c, code); } /* "warning" assert -- safe to continue, so we don't throw exception. */ NOINLINE_DECL void wasserted(const char* expr, const char* file, unsigned line) { static bool rateLimited; static time_t lastWhen; static unsigned lastLine; if (lastLine == line && time(0) - lastWhen < 5) { if (!rateLimited) { rateLimited = true; log() << "rate limiting wassert" << endl; } return; } lastWhen = time(0); lastLine = line; log() << "warning assertion failure " << expr << ' ' << file << ' ' << dec << line << endl; logContext(); } NOINLINE_DECL void verifyFailed(const char* expr, const char* file, unsigned line) { log() << "Assertion failure " << expr << ' ' << file << ' ' << dec << line << endl; logContext(); stringstream temp; temp << "assertion " << file << ":" << line; AssertionException e(temp.str(), 0); throw e; } NOINLINE_DECL void invariantFailed(const char* expr, const char* file, unsigned line) { log() << "Invariant failure " << expr << ' ' << file << ' ' << dec << line << endl; logContext(); log() << "\n\n***aborting after invariant() failure\n\n" << endl; abort(); } NOINLINE_DECL void invariantOKFailed(const char* expr, const Status& status, const char* file, unsigned line) { log() << "Invariant failure: " << expr << " resulted in status " << status << " at " << file << ' ' << dec << line; logContext(); log() << "\n\n***aborting after invariant() failure\n\n" << endl; abort(); } NOINLINE_DECL void fassertFailed(int msgid) { log() << "Fatal Assertion " << msgid << endl; logContext(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; abort(); } MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status) { log() << "Fatal assertion " << msgid << " " << status; logContext(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; abort(); } MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, const Status& status) { log() << "Fatal assertion " << msgid << " " << status; logContext(); log() << "\n\n***aborting after fassert() failure\n\n" << endl; abort(); } void uasserted(int msgid, const string& msg) { uasserted(msgid, msg.c_str()); } void UserException::appendPrefix(stringstream& ss) const { ss << "userassert:"; } void MsgAssertionException::appendPrefix(stringstream& ss) const { ss << "massert:"; } NOINLINE_DECL void uasserted(int msgid, const char* msg) { LOG(1) << "User Assertion: " << msgid << ":" << msg << endl; throw UserException(msgid, msg); } void msgasserted(int msgid, const string& msg) { msgasserted(msgid, msg.c_str()); } NOINLINE_DECL void msgasserted(int msgid, const char* msg) { log() << "Assertion: " << msgid << ":" << msg << endl; logContext(); throw MsgAssertionException(msgid, msg); } NOINLINE_DECL void msgassertedNoTrace(int msgid, const char* msg) { log() << "Assertion: " << msgid << ":" << msg << endl; throw MsgAssertionException(msgid, msg); } void msgassertedNoTrace(int msgid, const std::string& msg) { msgassertedNoTrace(msgid, msg.c_str()); } std::string causedBy(const char* e) { return std::string(" :: caused by :: ") + e; } std::string causedBy(const DBException& e) { return causedBy(e.toString()); } std::string causedBy(const std::exception& e) { return causedBy(e.what()); } std::string causedBy(const std::string& e) { return causedBy(e.c_str()); } std::string causedBy(const std::string* e) { return (e && *e != "") ? causedBy(*e) : ""; } std::string causedBy(const Status& e) { return causedBy(e.reason()); } string errnoWithPrefix(const char* prefix) { stringstream ss; if (prefix) ss << prefix << ": "; ss << errnoWithDescription(); return ss.str(); } string demangleName(const type_info& typeinfo) { #ifdef _WIN32 return typeinfo.name(); #else int status; char* niceName = abi::__cxa_demangle(typeinfo.name(), 0, 0, &status); if (!niceName) return typeinfo.name(); string s = niceName; free(niceName); return s; #endif } string ExceptionInfo::toString() const { stringstream ss; ss << "exception: " << code << " " << msg; return ss.str(); } NOINLINE_DECL ErrorMsg::ErrorMsg(const char* msg, char ch) { int l = strlen(msg); verify(l < 128); memcpy(buf, msg, l); char* p = buf + l; p[0] = ch; p[1] = 0; } NOINLINE_DECL ErrorMsg::ErrorMsg(const char* msg, unsigned val) { int l = strlen(msg); verify(l < 128); memcpy(buf, msg, l); char* p = buf + l; sprintf(p, "%u", val); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/assert_util.h000066400000000000000000000354421273231111400235620ustar00rootroot00000000000000// assert_util.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/status.h" // NOTE: This is safe as utils depend on base #include "mongo/client/export_macros.h" #include "mongo/platform/compiler.h" #include "mongo/logger/log_severity.h" #include "mongo/logger/logger.h" #include "mongo/logger/logstream_builder.h" namespace mongo { enum CommonErrorCodes { OkCode = 0, DatabaseDifferCaseCode = 13297, // uassert( 13297 ) SendStaleConfigCode = 13388, // uassert( 13388 ) RecvStaleConfigCode = 9996, // uassert( 9996 ) PrepareConfigsFailedCode = 13104, // uassert( 13104 ) NotMasterOrSecondaryCode = 13436, // uassert( 13436 ) NotMasterNoSlaveOkCode = 13435, // uassert( 13435 ) NotMaster = 10107, // uassert( 10107 ) }; class BSONObjBuilder; struct MONGO_CLIENT_API ExceptionInfo { ExceptionInfo() : msg(""), code(-1) {} ExceptionInfo(const char* m, int c) : msg(m), code(c) {} ExceptionInfo(const std::string& m, int c) : msg(m), code(c) {} void append(BSONObjBuilder& b, const char* m = "$err", const char* c = "code") const; std::string toString() const; bool empty() const { return msg.empty(); } void reset() { msg = ""; code = -1; } std::string msg; int code; }; /** helper class that builds error strings. lighter weight than a StringBuilder, albeit less * flexible. NOINLINE_DECL used in the constructor implementations as we are assuming this is a cold code path when used. example: throw UserException(123, ErrorMsg("blah", num_val)); */ class MONGO_CLIENT_API ErrorMsg { public: ErrorMsg(const char* msg, char ch); ErrorMsg(const char* msg, unsigned val); operator std::string() const { return buf; } private: char buf[256]; }; class DBException; MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const DBException& e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string& e); /** Most mongo exceptions inherit from this; this is commonly caught in most threads */ class MONGO_CLIENT_API DBException : public std::exception { public: DBException(const ExceptionInfo& ei) : _ei(ei) {} DBException(const char* msg, int code) : _ei(msg, code) {} DBException(const std::string& msg, int code) : _ei(msg, code) {} virtual ~DBException() throw() {} virtual const char* what() const throw() { return _ei.msg.c_str(); } virtual int getCode() const { return _ei.code; } virtual void appendPrefix(std::stringstream& ss) const {} virtual void addContext(const std::string& str) { _ei.msg = str + causedBy(_ei.msg); } // Utilities for the migration to Status objects static ErrorCodes::Error MONGO_CLIENT_FUNC convertExceptionCode(int exCode); Status toStatus(const std::string& context) const { return Status(convertExceptionCode(getCode()), context + causedBy(*this)); } Status toStatus() const { return Status(convertExceptionCode(getCode()), this->what()); } // context when applicable. otherwise "" std::string _shard; virtual std::string toString() const; const ExceptionInfo& getInfo() const { return _ei; } protected: ExceptionInfo _ei; }; class MONGO_CLIENT_API AssertionException : public DBException { public: AssertionException(const ExceptionInfo& ei) : DBException(ei) {} AssertionException(const char* msg, int code) : DBException(msg, code) {} AssertionException(const std::string& msg, int code) : DBException(msg, code) {} virtual ~AssertionException() throw() {} virtual bool severe() const { return true; } virtual bool isUserAssertion() const { return false; } }; /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */ class MONGO_CLIENT_API UserException : public AssertionException { public: UserException(int c, const std::string& m) : AssertionException(m, c) {} virtual bool severe() const { return false; } virtual bool isUserAssertion() const { return true; } virtual void appendPrefix(std::stringstream& ss) const; }; class MONGO_CLIENT_API MsgAssertionException : public AssertionException { public: MsgAssertionException(const ExceptionInfo& ei) : AssertionException(ei) {} MsgAssertionException(int c, const std::string& m) : AssertionException(m, c) {} virtual bool severe() const { return false; } virtual void appendPrefix(std::stringstream& ss) const; }; MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC verifyFailed(const char* expr, const char* file, unsigned line); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC invariantFailed(const char* expr, const char* file, unsigned line); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC invariantOKFailed(const char* expr, const Status& status, const char* file, unsigned line); MONGO_CLIENT_API void MONGO_CLIENT_FUNC wasserted(const char* expr, const char* file, unsigned line); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC fassertFailed(int msgid); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC fassertFailedWithStatus(int msgid, const Status& status); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC fassertFailedWithStatusNoTrace(int msgid, const Status& status); /** a "user assertion". throws UserAssertion. logs. typically used for errors that a user could cause, such as duplicate key, disk full, etc. */ MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC uasserted(int msgid, const char* msg); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC uasserted(int msgid, const std::string& msg); /** msgassert and massert are for errors that are internal but have a well defined error text std::string. a stack trace is logged. */ MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC msgassertedNoTrace(int msgid, const char* msg); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC msgassertedNoTrace(int msgid, const std::string& msg); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC msgasserted(int msgid, const char* msg); MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC msgasserted(int msgid, const std::string& msg); /* convert various types of exceptions to strings */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const char* e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const DBException& e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::exception& e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string& e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string* e); MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const Status& e); /** aborts on condition failure */ MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC fassert(int msgid, bool testOK) { if (MONGO_unlikely(!testOK)) fassertFailed(msgid); } MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC fassert(int msgid, const Status& status) { if (MONGO_unlikely(!status.isOK())) { fassertFailedWithStatus(msgid, status); } } MONGO_CLIENT_API inline void fassertNoTrace(int msgid, const Status& status) { if (MONGO_unlikely(!status.isOK())) { fassertFailedWithStatusNoTrace(msgid, status); } } /* "user assert". if asserts, user did something wrong, not our code */ #define MONGO_uassert(msgid, msg, expr) \ do { \ if (MONGO_unlikely(!(expr))) { \ ::mongo::uasserted(msgid, msg); \ } \ } while (false) MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC uassertStatusOK(const Status& status) { if (MONGO_unlikely(!status.isOK())) { uasserted((status.location() != 0 ? status.location() : status.code()), status.reason()); } } /* warning only - keeps going */ #define MONGO_wassert(_Expression) \ do { \ if (MONGO_unlikely(!(_Expression))) { \ ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \ } \ } while (false) /* display a message, no context, and throw assertionexception easy way to throw an exception and log something without our stack trace display happening. */ #define MONGO_massert(msgid, msg, expr) \ do { \ if (MONGO_unlikely(!(expr))) { \ ::mongo::msgasserted(msgid, msg); \ } \ } while (false) MONGO_CLIENT_API inline void massertStatusOK(const Status& status) { if (MONGO_unlikely(!status.isOK())) { msgasserted((status.location() != 0 ? status.location() : status.code()), status.reason()); } } MONGO_CLIENT_API inline void massertNoTraceStatusOK(const Status& status) { if (MONGO_unlikely(!status.isOK())) { msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()), status.reason()); } } /* same as massert except no msgid */ #define MONGO_verify(_Expression) \ do { \ if (MONGO_unlikely(!(_Expression))) { \ ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \ } \ } while (false) #define MONGO_invariant(_Expression) \ do { \ if (MONGO_unlikely(!(_Expression))) { \ ::mongo::invariantFailed(#_Expression, __FILE__, __LINE__); \ } \ } while (false) #define MONGO_invariantOK(expression) \ do { \ const ::mongo::Status _invariantOK_status = expression; \ if (MONGO_unlikely(!_invariantOK_status.isOK())) { \ ::mongo::invariantOKFailed(#expression, _invariantOK_status, __FILE__, __LINE__); \ } \ } while (false) #ifdef MONGO_EXPOSE_MACROS #define verify(expression) MONGO_verify(expression) #define invariant MONGO_invariant #define invariantOK MONGO_invariantOK #define uassert MONGO_uassert #define wassert MONGO_wassert #define massert MONGO_massert #endif // some special ids that we want to duplicate // > 10000 asserts // < 10000 UserException enum { ASSERT_ID_DUPKEY = 11000 }; std::string demangleName(const std::type_info& typeinfo); } // namespace mongo #define MONGO_ASSERT_ON_EXCEPTION(expression) \ try { \ expression; \ } catch (const std::exception& e) { \ std::stringstream ss; \ ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \ msgasserted(13294, ss.str()); \ } catch (...) { \ massert(10437, "unknown exception", false); \ } #define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG(expression, msg) \ try { \ expression; \ } catch (const std::exception& e) { \ std::stringstream ss; \ ss << msg << " caught exception exception: " << e.what(); \ msgasserted(14043, ss.str()); \ } catch (...) { \ msgasserted(14044, std::string("unknown exception") + msg); \ } #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define MONGO_DESTRUCTOR_GUARD(expression) \ try { \ expression; \ } catch (const std::exception& e) { \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::logger::LogSeverity::Log()) \ << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" \ << std::endl; \ } catch (...) { \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::logger::LogSeverity::Log()) \ << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << std::endl; \ } /** * The purpose of this macro is to instruct the compiler that a line of code will never be reached. * * Example: * // code above checks that expr can only be FOO or BAR * switch (expr) { * case FOO: { ... } * case BAR: { ... } * default: * MONGO_UNREACHABLE; */ #define MONGO_UNREACHABLE ::mongo::invariantFailed("Hit a MONGO_UNREACHABLE!", __FILE__, __LINE__); mongo-cxx-driver-legacy-1.1.2/src/mongo/util/background.cpp000066400000000000000000000110631273231111400236670ustar00rootroot00000000000000// @file background.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand #include "mongo/platform/basic.h" #include "mongo/util/background.h" #include #include #include #include #include "mongo/stdx/functional.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/time_support.h" #include "mongo/util/timer.h" using namespace std; namespace mongo { // both the BackgroundJob and the internal thread point to JobStatus struct BackgroundJob::JobStatus { JobStatus() : mutex(), state(NotStarted) {} boost::mutex mutex; boost::condition_variable done; State state; }; BackgroundJob::BackgroundJob(bool selfDelete) : _selfDelete(selfDelete), _status(new JobStatus) {} BackgroundJob::~BackgroundJob() {} void BackgroundJob::jobBody() { LOG(1) << "BackgroundJob starting" << endl; try { run(); } catch (const std::exception& e) { error() << "backgroundjob " << e.what(); throw; } // We must cache this value so that we can use it after we leave the following scope. const bool selfDelete = _selfDelete; #ifdef MONGO_SSL // TODO(sverch): Allow people who use the BackgroundJob to also specify cleanup tasks. // Currently the networking code depends on this class and this class depends on the // networking code because of this ad hoc cleanup. SSLManagerInterface* manager = getSSLManager(); if (manager) manager->cleanupThreadLocals(); #endif { // It is illegal to access any state owned by this BackgroundJob after leaving this // scope, with the exception of the call to 'delete this' below. boost::lock_guard l(_status->mutex); _status->state = Done; _status->done.notify_all(); } if (selfDelete) delete this; } void BackgroundJob::go() { boost::lock_guard l(_status->mutex); massert(17234, mongoutils::str::stream() << "backgroundJob already running: " << name(), _status->state != Running); // If the job is already 'done', for instance because it was cancelled or already // finished, ignore additional requests to run the job. if (_status->state == NotStarted) { boost::thread t(stdx::bind(&BackgroundJob::jobBody, this)); _status->state = Running; t.detach(); } } Status BackgroundJob::cancel() { boost::lock_guard l(_status->mutex); if (_status->state == Running) return Status(ErrorCodes::IllegalOperation, "Cannot cancel a running BackgroundJob"); if (_status->state == NotStarted) { _status->state = Done; _status->done.notify_all(); } return Status::OK(); } namespace { inline boost::xtime incxtimemillis(long long s) { boost::xtime xt; boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC); xt.sec += (int)(s / 1000); xt.nsec += (int)((s % 1000) * 1000000); if (xt.nsec >= 1000000000) { xt.nsec -= 1000000000; xt.sec++; } return xt; } } // namespace bool BackgroundJob::wait(unsigned msTimeOut) { verify(!_selfDelete); // you cannot call wait on a self-deleting job boost::unique_lock l(_status->mutex); while (_status->state != Done) { if (msTimeOut) { boost::xtime deadline = incxtimemillis(msTimeOut); if (!_status->done.timed_wait(l, deadline)) return false; } else { _status->done.wait(l); } } return true; } BackgroundJob::State BackgroundJob::getState() const { boost::lock_guard l(_status->mutex); return _status->state; } bool BackgroundJob::running() const { boost::lock_guard l(_status->mutex); return _status->state == Running; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/background.h000066400000000000000000000073251273231111400233420ustar00rootroot00000000000000// @file background.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/base/status.h" namespace mongo { /** * Background thread dispatching. * subclass and define run() * * It is not possible to run the job more than once. An attempt to call 'go' while the * task is running will fail. Calling 'go' after the task has finished are ignored and * will not start the job again. * * Thread safety: Note that when the job destructs, the thread is not terminated if still * running. Generally, if the thread could still be running, allocate the job dynamically * and set deleteSelf to true. * * The overridden run() method will be executed on the background thread, so the * BackgroundJob object must exist for as long the background thread is running. */ class BackgroundJob : boost::noncopyable { protected: /** * sub-class must instantiate the BackgroundJob * * @param selfDelete if set to true, object will destruct itself after the run() finished * @note selfDelete instances cannot be wait()-ed upon */ explicit BackgroundJob(bool selfDelete = false); virtual std::string name() const = 0; /** * define this to do your work. * after this returns, state is set to done. * after this returns, deleted if deleteSelf true. * * NOTE: * if run() throws, the exception will be caught within 'this' object and will ultimately lead * to the BackgroundJob's thread being finished, as if run() returned. * */ virtual void run() = 0; public: enum State { NotStarted, Running, Done }; virtual ~BackgroundJob(); /** * starts job. * returns immediately after dispatching. * * @note the BackgroundJob object must live for as long the thread is still running, ie * until getState() returns Done. */ void go(); /** * If the job has not yet started, transitions the job to the 'done' state immediately, * such that subsequent calls to 'go' are ignored, and notifies any waiters waiting in * 'wait'. If the job has already been started, this method returns a not-ok status: it * does not cancel running jobs. For this reason, you must still call 'wait' on a * BackgroundJob even after calling 'cancel'. */ Status cancel(); /** * wait for completion. * * @param msTimeOut maximum amount of time to wait in milliseconds * @return true if did not time out. false otherwise. * * @note you can call wait() more than once if the first call times out. * but you cannot call wait on a self-deleting job. */ bool wait(unsigned msTimeOut = 0); // accessors. Note that while the access to the internal state is synchronized within // these methods, there is no guarantee that the BackgroundJob is still in the // indicated state after returning. State getState() const; bool running() const; private: const bool _selfDelete; struct JobStatus; const boost::scoped_ptr _status; void jobBody(); }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/base64.cpp000066400000000000000000000060731273231111400226410ustar00rootroot00000000000000// util/base64.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/base64.h" #include #include "mongo/util/assert_util.h" namespace mongo { namespace base64 { using std::string; using std::stringstream; Alphabet alphabet; void Alphabet::test() { verify(strlen((char*)encode) == 64); for (int i = 0; i < 26; i++) verify(encode[i] == toupper(encode[i + 26])); } void encode(stringstream& ss, const char* data, int size) { for (int i = 0; i < size; i += 3) { int left = size - i; const unsigned char* start = (const unsigned char*)data + i; // byte 0 ss << alphabet.e(start[0] >> 2); // byte 1 unsigned char temp = (start[0] << 4); if (left == 1) { ss << alphabet.e(temp); break; } temp |= ((start[1] >> 4) & 0xF); ss << alphabet.e(temp); // byte 2 temp = (start[1] & 0xF) << 2; if (left == 2) { ss << alphabet.e(temp); break; } temp |= ((start[2] >> 6) & 0x3); ss << alphabet.e(temp); // byte 3 ss << alphabet.e(start[2] & 0x3f); } int mod = size % 3; if (mod == 1) { ss << "=="; } else if (mod == 2) { ss << "="; } } string encode(const char* data, int size) { stringstream ss; encode(ss, data, size); return ss.str(); } string encode(const string& s) { return encode(s.c_str(), s.size()); } void decode(stringstream& ss, const string& s) { uassert(10270, "invalid base64", s.size() % 4 == 0); const unsigned char* data = (const unsigned char*)s.c_str(); int size = s.size(); unsigned char buf[3]; for (int i = 0; i < size; i += 4) { const unsigned char* start = data + i; buf[0] = ((alphabet.decode[start[0]] << 2) & 0xFC) | ((alphabet.decode[start[1]] >> 4) & 0x3); buf[1] = ((alphabet.decode[start[1]] << 4) & 0xF0) | ((alphabet.decode[start[2]] >> 2) & 0xF); buf[2] = ((alphabet.decode[start[2]] << 6) & 0xC0) | ((alphabet.decode[start[3]] & 0x3F)); int len = 3; if (start[3] == '=') { len = 2; if (start[2] == '=') { len = 1; } } ss.write((const char*)buf, len); } } string decode(const string& s) { stringstream ss; decode(ss, s); return ss.str(); } const char* chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/="; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/base64.h000066400000000000000000000033271273231111400223050ustar00rootroot00000000000000// util/base64.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include namespace mongo { namespace base64 { class Alphabet { public: Alphabet() : encode((unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "+/") , decode(new unsigned char[257]) { memset(decode.get(), 0, 256); for (int i = 0; i < 64; i++) { decode[encode[i]] = i; } test(); } void test(); char e(int x) { return encode[x & 0x3f]; } private: const unsigned char* encode; public: boost::scoped_array decode; }; extern Alphabet alphabet; void encode(std::stringstream& ss, const char* data, int size); std::string encode(const char* data, int size); std::string encode(const std::string& s); void decode(std::stringstream& ss, const std::string& s); std::string decode(const std::string& s); extern const char* chars; void testAlphabet(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/concurrency/000077500000000000000000000000001273231111400233755ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/util/concurrency/synchronization.cpp000066400000000000000000000037521273231111400273510ustar00rootroot00000000000000// synchronization.cpp /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/concurrency/synchronization.h" #include #include #include "mongo/util/assert_util.h" namespace mongo { Notification::Notification() : _mutex() { lookFor = 1; cur = 0; } void Notification::waitToBeNotified() { boost::unique_lock lock(_mutex); while (lookFor != cur) _condition.wait(lock); lookFor++; } void Notification::notifyOne() { boost::lock_guard lock(_mutex); verify(cur != lookFor); cur++; _condition.notify_one(); } /* --- NotifyAll --- */ NotifyAll::NotifyAll() : _mutex() { _lastDone = 0; _lastReturned = 0; _nWaiting = 0; } NotifyAll::When NotifyAll::now() { boost::lock_guard lock(_mutex); return ++_lastReturned; } void NotifyAll::waitFor(When e) { boost::unique_lock lock(_mutex); ++_nWaiting; while (_lastDone < e) { _condition.wait(lock); } } void NotifyAll::awaitBeyondNow() { boost::unique_lock lock(_mutex); ++_nWaiting; When e = ++_lastReturned; while (_lastDone <= e) { _condition.wait(lock); } } void NotifyAll::notifyAll(When e) { boost::lock_guard lock(_mutex); _lastDone = e; _nWaiting = 0; _condition.notify_all(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/concurrency/synchronization.h000066400000000000000000000045171273231111400270160ustar00rootroot00000000000000// synchronization.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include namespace mongo { /* * A class to establish a synchronization point between two threads. One thread is the waiter * and one is the notifier. After the notification event, both proceed normally. * * This class is thread-safe. */ class Notification : boost::noncopyable { public: Notification(); /* * Blocks until the method 'notifyOne()' is called. */ void waitToBeNotified(); /* * Notifies the waiter of '*this' that it can proceed. Can only be called once. */ void notifyOne(); private: boost::mutex _mutex; // protects state below unsigned long long lookFor; unsigned long long cur; boost::condition_variable _condition; // cond over _notified being true }; /** establishes a synchronization point between threads. N threads are waits and one is notifier. threadsafe. */ class NotifyAll : boost::noncopyable { public: NotifyAll(); typedef unsigned long long When; When now(); /** awaits the next notifyAll() call by another thread. notifications that precede this call are ignored -- we are looking for a fresh event. */ void waitFor(When); /** a bit faster than waitFor( now() ) */ void awaitBeyondNow(); /** may be called multiple times. notifies all waiters */ void notifyAll(When); /** indicates how many threads are waiting for a notify. */ unsigned nWaiting() const { return _nWaiting; } private: boost::mutex _mutex; boost::condition_variable _condition; When _lastDone; When _lastReturned; unsigned _nWaiting; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/concurrency/threadlocal.h000066400000000000000000000103471273231111400260350ustar00rootroot00000000000000#pragma once /* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/client/undef_macros.h" #include #include "mongo/client/redef_macros.h" namespace mongo { /* thread local "value" rather than a pointer good for things which have copy constructors (and the copy constructor is fast enough) e.g. ThreadLocalValue myint; */ template class ThreadLocalValue { public: ThreadLocalValue(T def = 0) : _default(def) {} T get() const { T* val = _val.get(); if (val) return *val; return _default; } void set(const T& i) { T* v = _val.get(); if (v) { *v = i; return; } v = new T(i); _val.reset(v); } T& getRef() { T* v = _val.get(); if (v) { return *v; } v = new T(_default); _val.reset(v); return *v; } private: boost::thread_specific_ptr _val; const T _default; }; /* TSP These macros use intrinsics which are faster than boost::thread_specific_ptr. However the intrinsics don't free up objects on thread closure. Thus we use a combination here, with the assumption that reset's are infrequent, so that get's are fast. */ #if defined(MONGO_HAVE___THREAD) || defined(MONGO_HAVE___DECLSPEC_THREAD) template struct TSP { boost::thread_specific_ptr tsp; public: T* get() const; void reset(T* v); T* getMake() { T* t = get(); if (t == 0) reset(t = new T()); return t; } }; #if defined(MONGO_HAVE___DECLSPEC_THREAD) #define TSP_DECLARE(T, p) extern TSP p; #define TSP_DEFINE(T, p) \ __declspec(thread) T* _##p; \ TSP p; \ template <> \ T* TSP::get() const { \ return _##p; \ } \ void TSP::reset(T* v) { \ tsp.reset(v); \ _##p = v; \ } #else #define TSP_DECLARE(T, p) \ extern __thread T* _##p; \ template <> \ inline T* TSP::get() const { \ return _##p; \ } \ extern TSP p; #define TSP_DEFINE(T, p) \ __thread T* _##p; \ template <> \ void TSP::reset(T* v) { \ tsp.reset(v); \ _##p = v; \ } \ TSP p; #endif #elif defined(_POSIX_THREADS) && (_POSIX_THREADS >= 0) template struct TSP { pthread_key_t _key; public: TSP() { verify(pthread_key_create(&_key, TSP::dodelete) == 0); } ~TSP() { pthread_key_delete(_key); } static void dodelete(void* x) { T* t = reinterpret_cast(x); delete t; } T* get() const { return reinterpret_cast(pthread_getspecific(_key)); } void reset(T* v) { T* old = get(); delete old; verify(pthread_setspecific(_key, v) == 0); } T* getMake() { T* t = get(); if (t == 0) { t = new T(); reset(t); } return t; } }; #define TSP_DECLARE(T, p) extern TSP p; #define TSP_DEFINE(T, p) TSP p; #else template struct TSP { boost::thread_specific_ptr tsp; public: T* get() const { return tsp.get(); } void reset(T* v) { tsp.reset(v); } T* getMake() { T* t = get(); if (t == 0) reset(t = new T()); return t; } }; #define TSP_DECLARE(T, p) extern TSP p; #define TSP_DEFINE(T, p) TSP p; #endif } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/debug_util.h000066400000000000000000000021301273231111400233330ustar00rootroot00000000000000// debug_util.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { #if defined(MONGO_DEBUG_BUILD) const bool debug = true; #else const bool debug = false; #endif #define MONGO_DEV if (debug) #define DEV MONGO_DEV /* dassert is 'debug assert' -- might want to turn off for production as these could be slow. */ #if defined(MONGO_DEBUG_BUILD) #define MONGO_dassert(x) invariant(x) #else #define MONGO_dassert(x) #endif #ifdef MONGO_EXPOSE_MACROS #define dassert MONGO_dassert #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/embedded_builder.h000066400000000000000000000057771273231111400244730ustar00rootroot00000000000000// embedded_builder.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { // utility class for assembling hierarchical objects class EmbeddedBuilder { public: EmbeddedBuilder(BSONObjBuilder* b) { _builders.push_back(std::make_pair("", b)); } // It is assumed that the calls to prepareContext will be made with the 'name' // parameter in lex ascending order. void prepareContext(std::string& name) { int i = 1, n = _builders.size(); while ( i < n && name.substr(0, _builders[i].first.length()) == _builders[i].first && (name[_builders[i].first.length()] == '.' || name[_builders[i].first.length()] == 0)) { name = name.substr(_builders[i].first.length() + 1); ++i; } for (int j = n - 1; j >= i; --j) { popBuilder(); } for (std::string next = splitDot(name); !next.empty(); next = splitDot(name)) { addBuilder(next); } } void appendAs(const BSONElement& e, std::string name) { if (e.type() == Object && e.valuesize() == 5) { // empty object -- this way we can add to it later std::string dummyName = name + ".foo"; prepareContext(dummyName); return; } prepareContext(name); back()->appendAs(e, name); } BufBuilder& subarrayStartAs(std::string name) { prepareContext(name); return back()->subarrayStart(name); } void done() { while (!_builderStorage.empty()) popBuilder(); } static std::string splitDot(std::string& str) { size_t pos = str.find('.'); if (pos == std::string::npos) return ""; std::string ret = str.substr(0, pos); str = str.substr(pos + 1); return ret; } private: void addBuilder(const std::string& name) { boost::shared_ptr newBuilder(new BSONObjBuilder(back()->subobjStart(name))); _builders.push_back(std::make_pair(name, newBuilder.get())); _builderStorage.push_back(newBuilder); } void popBuilder() { back()->done(); _builders.pop_back(); _builderStorage.pop_back(); } BSONObjBuilder* back() { return _builders.back().second; } std::vector > _builders; std::vector > _builderStorage; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point.cpp000066400000000000000000000102311273231111400236700ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl #include "mongo/util/fail_point.h" #include #include "mongo/util/mongoutils/str.h" #include "mongo/util/log.h" #include "mongo/util/time_support.h" using mongoutils::str::stream; namespace mongo { using std::endl; FailPoint::FailPoint() : _fpInfo(0), _mode(off), _timesOrPeriod(0), _modMutex() {} void FailPoint::shouldFailCloseBlock() { _fpInfo.subtractAndFetch(1); } void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) { /** * Outline: * * 1. Deactivates fail point to enter write-only mode * 2. Waits for all current readers of the fail point to finish * 3. Sets the new mode. */ boost::lock_guard scoped(_modMutex); // Step 1 disableFailPoint(); // Step 2 while (_fpInfo.load() != 0) { sleepmillis(50); } // Step 3 uassert(16442, stream() << "mode not supported " << static_cast(mode), mode >= off && mode < numModes); _mode = mode; _timesOrPeriod.store(val); _data = extra.copy(); if (_mode != off) { enableFailPoint(); } } const BSONObj& FailPoint::getData() const { return _data; } void FailPoint::enableFailPoint() { // TODO: Better to replace with a bitwise OR, once available for AU32 ValType currentVal = _fpInfo.load(); ValType expectedCurrentVal; ValType newVal; do { expectedCurrentVal = currentVal; newVal = expectedCurrentVal | ACTIVE_BIT; currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal); } while (expectedCurrentVal != currentVal); } void FailPoint::disableFailPoint() { // TODO: Better to replace with a bitwise AND, once available for AU32 ValType currentVal = _fpInfo.load(); ValType expectedCurrentVal; ValType newVal; do { expectedCurrentVal = currentVal; newVal = expectedCurrentVal & REF_COUNTER_MASK; currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal); } while (expectedCurrentVal != currentVal); } FailPoint::RetCode FailPoint::slowShouldFailOpenBlock() { ValType localFpInfo = _fpInfo.addAndFetch(1); if ((localFpInfo & ACTIVE_BIT) == 0) { return slowOff; } switch (_mode) { case alwaysOn: return slowOn; case random: // TODO: randomly determine if should be active or not error() << "FailPoint Mode random is not yet supported." << endl; fassertFailed(16443); case nTimes: { AtomicInt32::WordType newVal = _timesOrPeriod.subtractAndFetch(1); if (newVal <= 0) { disableFailPoint(); } return slowOn; } default: error() << "FailPoint Mode not supported: " << static_cast(_mode) << endl; fassertFailed(16444); } } BSONObj FailPoint::toBSON() const { BSONObjBuilder builder; boost::lock_guard scoped(_modMutex); builder.append("mode", _mode); builder.append("data", _data); return builder.obj(); } ScopedFailPoint::ScopedFailPoint(FailPoint* failPoint) : _failPoint(failPoint), _once(false), _shouldClose(false) {} ScopedFailPoint::~ScopedFailPoint() { if (_shouldClose) { _failPoint->shouldFailCloseBlock(); } } const BSONObj& ScopedFailPoint::getData() const { // Assert when attempting to get data without incrementing ref counter. fassert(16445, _shouldClose); return _failPoint->getData(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point.h000066400000000000000000000141541273231111400233450ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" #include "mongo/db/jsobj.h" #include "mongo/platform/atomic_word.h" namespace mongo { /** * A simple thread-safe fail point implementation that can be activated and * deactivated, as well as embed temporary data into it. * * The fail point has a static instance, which is represented by a FailPoint * object, and dynamic instance, which are all the threads in between * shouldFailOpenBlock and shouldFailCloseBlock. * * Sample use: * // Declared somewhere: * FailPoint makeBadThingsHappen; * * // Somewhere in the code * return false || MONGO_FAIL_POINT(makeBadThingsHappen); * * or * * // Somewhere in the code * MONGO_FAIL_POINT_BLOCK(makeBadThingsHappen, blockMakeBadThingsHappen) { * const BSONObj& data = blockMakeBadThingsHappen.getData(); * // Do something * } * * Invariants: * * 1. Always refer to _fpInfo first to check if failPoint is active or not before * entering fail point or modifying fail point. * 2. Client visible fail point states are read-only when active. */ class FailPoint { MONGO_DISALLOW_COPYING(FailPoint); public: typedef AtomicUInt32::WordType ValType; enum Mode { off, alwaysOn, random, nTimes, numModes }; enum RetCode { fastOff = 0, slowOff, slowOn }; FailPoint(); /** * Note: This is not side-effect free - it can change the state to OFF after calling. * * @return true if fail point is active. */ inline bool shouldFail() { RetCode ret = shouldFailOpenBlock(); if (MONGO_likely(ret == fastOff)) { return false; } shouldFailCloseBlock(); return ret == slowOn; } /** * Checks whether fail point is active and increments the reference counter without * decrementing it. Must call shouldFailCloseBlock afterwards when the return value * is not fastOff. Otherwise, this will remain read-only forever. * * @return slowOn if fail point is active. */ inline RetCode shouldFailOpenBlock() { if (MONGO_likely((_fpInfo.loadRelaxed() & ACTIVE_BIT) == 0)) { return fastOff; } return slowShouldFailOpenBlock(); } /** * Decrements the reference counter. * @see #shouldFailOpenBlock */ void shouldFailCloseBlock(); /** * Changes the settings of this fail point. This will turn off the fail point * and waits for all dynamic instances referencing this fail point to go away before * actually modifying the settings. * * @param mode the new mode for this fail point. * @param val the value that can have different usage depending on the mode: * * - off, alwaysOn: ignored * - random: * - nTimes: the number of times this fail point will be active when * #shouldFail or #shouldFailOpenBlock is called. * * @param extra arbitrary BSON object that can be stored to this fail point * that can be referenced afterwards with #getData. Defaults to an empty * document. */ void setMode(Mode mode, ValType val = 0, const BSONObj& extra = BSONObj()); /** * @returns a BSON object showing the current mode and data stored. */ BSONObj toBSON() const; private: static const ValType ACTIVE_BIT = 1 << 31; static const ValType REF_COUNTER_MASK = ~ACTIVE_BIT; // Bit layout: // 31: tells whether this fail point is active. // 0~30: unsigned ref counter for active dynamic instances. AtomicUInt32 _fpInfo; // Invariant: These should be read only if ACTIVE_BIT of _fpInfo is set. Mode _mode; AtomicInt32 _timesOrPeriod; BSONObj _data; // protects _mode, _timesOrPeriod, _data mutable boost::mutex _modMutex; /** * Enables this fail point. */ void enableFailPoint(); /** * Disables this fail point. */ void disableFailPoint(); /** * slow path for #shouldFailOpenBlock */ RetCode slowShouldFailOpenBlock(); /** * @return the stored BSONObj in this fail point. Note that this cannot be safely * read if this fail point is off. */ const BSONObj& getData() const; friend class ScopedFailPoint; }; /** * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when * FailPoint#shouldFailOpenBlock was called. This should only be used within the * MONGO_FAIL_POINT_BLOCK macro. */ class ScopedFailPoint { MONGO_DISALLOW_COPYING(ScopedFailPoint); public: ScopedFailPoint(FailPoint* failPoint); ~ScopedFailPoint(); /** * @return true if fail point is on. This will be true at most once. */ inline bool isActive() { if (_once) { return false; } _once = true; FailPoint::RetCode ret = _failPoint->shouldFailOpenBlock(); _shouldClose = ret != FailPoint::fastOff; return ret == FailPoint::slowOn; } /** * @return the data stored in the fail point. #isActive must be true * before you can call this. */ const BSONObj& getData() const; private: FailPoint* _failPoint; bool _once; bool _shouldClose; }; #define MONGO_FAIL_POINT(symbol) MONGO_unlikely(symbol.shouldFail()) /** * Macro for creating a fail point with block context. Also use this when * you want to access the data stored in the fail point. */ #define MONGO_FAIL_POINT_BLOCK(symbol, blockSymbol) \ for (mongo::ScopedFailPoint blockSymbol(&symbol); MONGO_unlikely(blockSymbol.isActive());) } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point_registry.cpp000066400000000000000000000027521273231111400256310ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/fail_point_registry.h" #include "mongo/util/map_util.h" #include "mongo/util/mongoutils/str.h" using mongoutils::str::stream; namespace mongo { using std::string; FailPointRegistry::FailPointRegistry() : _frozen(false) {} Status FailPointRegistry::addFailPoint(const string& name, FailPoint* failPoint) { if (_frozen) { return Status(ErrorCodes::CannotMutateObject, "Registry is already frozen"); } if (_fpMap.count(name) > 0) { return Status(ErrorCodes::DuplicateKey, stream() << "Fail point already registered: " << name); } _fpMap.insert(make_pair(name, failPoint)); return Status::OK(); } FailPoint* FailPointRegistry::getFailPoint(const string& name) const { return mapFindWithDefault(_fpMap, name, static_cast(NULL)); } void FailPointRegistry::freeze() { _frozen = true; } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point_registry.h000066400000000000000000000032501273231111400252700ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Should NOT be included by other header files. Include only in source files. */ #pragma once #include "mongo/base/status.h" #include "mongo/platform/unordered_map.h" #include "mongo/util/fail_point.h" namespace mongo { /** * Class for storing FailPoint instances. */ class FailPointRegistry { public: FailPointRegistry(); /** * Adds a new fail point to this registry. Duplicate names are not allowed. * * @return the status code under these circumstances: * OK - if successful. * DuplicateKey - if the given name already exists in this registry. * CannotMutateObject - if this registry is already frozen. */ Status addFailPoint(const std::string& name, FailPoint* failPoint); /** * @return the fail point object registered. Returns NULL if it was not registered. */ FailPoint* getFailPoint(const std::string& name) const; /** * Freezes this registry from being modified. */ void freeze(); private: bool _frozen; unordered_map _fpMap; }; } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point_service.cpp000066400000000000000000000025241273231111400254160ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/fail_point_service.h" #include namespace mongo { MONGO_FP_DECLARE(dummy); // used by jstests/libs/fail_point.js boost::scoped_ptr _fpRegistry(NULL); MONGO_INITIALIZER(FailPointRegistry)(InitializerContext* context) { _fpRegistry.reset(new FailPointRegistry()); return Status::OK(); } MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS)(InitializerContext* context) { _fpRegistry->freeze(); return Status::OK(); } FailPointRegistry* getGlobalFailPointRegistry() { return _fpRegistry.get(); } } MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(util_fail_point_service) mongo-cxx-driver-legacy-1.1.2/src/mongo/util/fail_point_service.h000066400000000000000000000031341273231111400250610ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/init.h" #include "mongo/util/fail_point_registry.h" namespace mongo { /** * @return the global fail point registry. */ FailPointRegistry* getGlobalFailPointRegistry(); /** * Convenience macro for declaring a fail point. Must be used in global scope and never in a * block with limited scope (ie, inside functions, loops, etc.). * * NOTE: Never use in header files, only sources. */ #define MONGO_FP_DECLARE(fp) \ FailPoint fp; \ MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPointsRegistered")) \ (::mongo::InitializerContext * context) { \ return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \ } /** * Convenience macro for defining a fail point in a header scope. */ #define MONGO_FP_FORWARD_DECLARE(fp) extern FailPoint fp; } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/hex.cpp000066400000000000000000000036001273231111400223320ustar00rootroot00000000000000// util/hex.cpp /* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "mongo/util/hex.h" namespace mongo { template std::string integerToHexDef(T inInt) { if (!inInt) return "0"; static const char hexchars[] = "0123456789ABCDEF"; static const size_t outbufSize = sizeof(T) * 2 + 1; char outbuf[outbufSize]; outbuf[outbufSize - 1] = '\0'; char c; int lastSeenNumber = 0; for (int j = int(outbufSize) - 2; j >= 0; j--) { c = hexchars[inInt & 0xF]; if (c != '0') lastSeenNumber = j; outbuf[j] = c; inInt = inInt >> 4; } char* bufPtr = outbuf; bufPtr += lastSeenNumber; return std::string(bufPtr); } template <> std::string integerToHex(int val) { return integerToHexDef(val); } template <> std::string integerToHex(unsigned int val) { return integerToHexDef(val); } template <> std::string integerToHex(long val) { return integerToHexDef(val); } template <> std::string integerToHex(unsigned long val) { return integerToHexDef(val); } template <> std::string integerToHex(long long val) { return integerToHexDef(val); } template <> std::string integerToHex(unsigned long long val) { return integerToHexDef(val); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/hex.h000066400000000000000000000041151273231111400220010ustar00rootroot00000000000000// util/hex.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/string_data.h" #include "mongo/bson/util/builder.h" namespace mongo { // can't use hex namespace because it conflicts with hex iostream function inline int fromHex(char c) { if ('0' <= c && c <= '9') return c - '0'; if ('a' <= c && c <= 'f') return c - 'a' + 10; if ('A' <= c && c <= 'F') return c - 'A' + 10; verify(false); return 0xff; } inline char fromHex(const char* c) { return (char)((fromHex(c[0]) << 4) | fromHex(c[1])); } inline char fromHex(const StringData& c) { return (char)((fromHex(c[0]) << 4) | fromHex(c[1])); } inline std::string toHex(const void* inRaw, int len) { static const char hexchars[] = "0123456789ABCDEF"; StringBuilder out; const char* in = reinterpret_cast(inRaw); for (int i = 0; i < len; ++i) { char c = in[i]; char hi = hexchars[(c & 0xF0) >> 4]; char lo = hexchars[(c & 0x0F)]; out << hi << lo; } return out.str(); } template std::string integerToHex(T val); inline std::string toHexLower(const void* inRaw, int len) { static const char hexchars[] = "0123456789abcdef"; StringBuilder out; const char* in = reinterpret_cast(inRaw); for (int i = 0; i < len; ++i) { char c = in[i]; char hi = hexchars[(c & 0xF0) >> 4]; char lo = hexchars[(c & 0x0F)]; out << hi << lo; } return out.str(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/log.cpp000066400000000000000000000057311273231111400223360ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl #include "mongo/platform/basic.h" #include "mongo/util/log.h" #ifdef _WIN32 #include #else #include #include #endif #include "mongo/util/assert_util.h" #include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/text.h" #include "mongo/util/time_support.h" using namespace std; // TODO: Win32 unicode console writing (in logger/console_appender?). // TODO: Extra log context appending, and re-enable log_user_*.js // TODO: Eliminate cout/cerr. namespace mongo { static logger::ExtraLogContextFn _appendExtraLogContext; Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) { if (!contextFn) return Status(ErrorCodes::BadValue, "Cannot register a NULL log context function."); if (_appendExtraLogContext) { return Status(ErrorCodes::AlreadyInitialized, "Cannot call registerExtraLogContextFn multiple times."); } _appendExtraLogContext = contextFn; return Status::OK(); } string errnoWithDescription(int x) { #if defined(_WIN32) if (x < 0) x = GetLastError(); #else if (x < 0) x = errno; #endif stringstream s; s << "errno:" << x << ' '; #if defined(_WIN32) LPWSTR errorText = NULL; FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, x, 0, reinterpret_cast(&errorText), // output 0, // minimum size for output buffer NULL); if (errorText) { string x = toUtf8String(errorText); for (string::iterator i = x.begin(); i != x.end(); i++) { if (*i == '\n' || *i == '\r') break; s << *i; } LocalFree(errorText); } else s << strerror(x); /* DWORD n = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, x, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); */ #else s << strerror(x); #endif return s.str(); } void logContext(const char* errmsg) { if (errmsg) { log() << errmsg << endl; } } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/log.h000066400000000000000000000212171273231111400220000ustar00rootroot00000000000000// @file log.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #pragma once is not used in this header. // This header attempts to enforce the rule that no logging should be done in // an inline function defined in a header. // To enforce this "no logging in header" rule, we use #include guards with a validating #else // clause. // Also, this header relies on a preprocessor macro to determine the default component for the // unconditional logging functions severe(), error(), warning() and log(). Disallowing multiple // inclusion of log.h will ensure that the default component will be set correctly. #if defined(MONGO_UTIL_LOG_H_) #error \ "mongo/util/log.h cannot be included multiple times. " \ "This may occur when log.h is included in a header. " \ "Please check your #include's." #else // MONGO_UTIL_LOG_H_ #define MONGO_UTIL_LOG_H_ #include "mongo/base/status.h" #include "mongo/bson/util/builder.h" #include "mongo/logger/log_component.h" #include "mongo/logger/logger.h" #include "mongo/logger/logstream_builder.h" #include "mongo/logger/tee.h" // Provide log component in global scope so that MONGO_LOG will always have a valid component. // Global log component will be kDefault unless overridden by MONGO_LOG_DEFAULT_COMPONENT. #if defined(MONGO_LOG_DEFAULT_COMPONENT) const ::mongo::logger::LogComponent MongoLogDefaultComponent_component = MONGO_LOG_DEFAULT_COMPONENT; #else #error \ "mongo/util/log.h requires MONGO_LOG_DEFAULT_COMPONENT to be defined. " \ "Please see http://www.mongodb.org/about/contributors/reference/server-logging-rules/ " #endif // MONGO_LOG_DEFAULT_COMPONENT namespace mongo { namespace logger { typedef void (*ExtraLogContextFn)(BufBuilder& builder); Status registerExtraLogContextFn(ExtraLogContextFn contextFn); } // namespace logger namespace { using logger::LogstreamBuilder; using logger::LabeledLevel; using logger::Tee; /** * Returns a LogstreamBuilder for logging a message with LogSeverity::Severe(). */ inline LogstreamBuilder severe() { return LogstreamBuilder(logger::globalLogDomain(), std::string(), logger::LogSeverity::Severe(), ::MongoLogDefaultComponent_component); } inline LogstreamBuilder severe(logger::LogComponent component) { return LogstreamBuilder( logger::globalLogDomain(), std::string(), logger::LogSeverity::Severe(), component); } /** * Returns a LogstreamBuilder for logging a message with LogSeverity::Error(). */ inline LogstreamBuilder error() { return LogstreamBuilder(logger::globalLogDomain(), std::string(), logger::LogSeverity::Error(), ::MongoLogDefaultComponent_component); } inline LogstreamBuilder error(logger::LogComponent component) { return LogstreamBuilder( logger::globalLogDomain(), std::string(), logger::LogSeverity::Error(), component); } /** * Returns a LogstreamBuilder for logging a message with LogSeverity::Warning(). */ inline LogstreamBuilder warning() { return LogstreamBuilder(logger::globalLogDomain(), std::string(), logger::LogSeverity::Warning(), ::MongoLogDefaultComponent_component); } inline LogstreamBuilder warning(logger::LogComponent component) { return LogstreamBuilder( logger::globalLogDomain(), std::string(), logger::LogSeverity::Warning(), component); } /** * Returns a LogstreamBuilder for logging a message with LogSeverity::Log(). */ inline LogstreamBuilder log() { return LogstreamBuilder(logger::globalLogDomain(), std::string(), logger::LogSeverity::Log(), ::MongoLogDefaultComponent_component); } inline LogstreamBuilder log(logger::LogComponent component) { return LogstreamBuilder( logger::globalLogDomain(), std::string(), logger::LogSeverity::Log(), component); } inline LogstreamBuilder log(logger::LogComponent::Value componentValue) { return LogstreamBuilder( logger::globalLogDomain(), std::string(), logger::LogSeverity::Log(), componentValue); } /** * Runs the same logic as log()/warning()/error(), without actually outputting a stream. */ inline bool shouldLog(logger::LogSeverity severity) { return logger::globalLogDomain()->shouldLog(::MongoLogDefaultComponent_component, severity); } } // namespace // MONGO_LOG uses log component from MongoLogDefaultComponent from current or global namespace. #define MONGO_LOG(DLEVEL) \ if (!(::mongo::logger::globalLogDomain()) \ ->shouldLog(MongoLogDefaultComponent_component, \ ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \ } else \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \ MongoLogDefaultComponent_component) #define LOG MONGO_LOG #define MONGO_LOG_COMPONENT(DLEVEL, COMPONENT1) \ if (!(::mongo::logger::globalLogDomain()) \ ->shouldLog((COMPONENT1), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \ } else \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \ (COMPONENT1)) #define MONGO_LOG_COMPONENT2(DLEVEL, COMPONENT1, COMPONENT2) \ if (!(::mongo::logger::globalLogDomain()) \ ->shouldLog( \ (COMPONENT1), (COMPONENT2), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \ } else \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \ (COMPONENT1)) #define MONGO_LOG_COMPONENT3(DLEVEL, COMPONENT1, COMPONENT2, COMPONENT3) \ if (!(::mongo::logger::globalLogDomain()) \ ->shouldLog((COMPONENT1), \ (COMPONENT2), \ (COMPONENT3), \ ::mongo::LogstreamBuilder::severityCast(DLEVEL))) { \ } else \ ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ std::string(), \ ::mongo::LogstreamBuilder::severityCast(DLEVEL), \ (COMPONENT1)) /** output the error # and error message with prefix. handy for use as parm in uassert/massert. */ std::string errnoWithPrefix(const char* prefix); std::string errnoWithDescription(int errorcode = -1); /** * Write the optional "msg". */ void logContext(const char* msg = NULL); } // namespace mongo #endif // MONGO_UTIL_LOG_H_ mongo-cxx-driver-legacy-1.1.2/src/mongo/util/map_util.h000066400000000000000000000020341273231111400230250ustar00rootroot00000000000000// "mongo/util/map_util.h" /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { /* * If "myMap" contains "key", returns "myMap[key]". Otherwise, returns "defaultValue." */ template V mapFindWithDefault(const M& myMap, const K& key, const V& defaultValue) { typename M::const_iterator it = myMap.find(key); if (it == myMap.end()) return defaultValue; return it->second; } } // end namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/util/md5.cpp000066400000000000000000000313251273231111400222400ustar00rootroot00000000000000/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* NOTE: Per restriction 2 above, this file has been altered by MongoDB as follows: 1. All contents of this file have been moved within the 'mongo' namespace and the extern "C" block has been removed. */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include namespace mongo { #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN #define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else #define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t* X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t*)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t*)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t*)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t* xp = data; int i; #if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ #else #define xbuf X /* (static only) */ #endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + F(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + G(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti) \ t = a + H(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + I(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t* pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes) { const md5_byte_t* p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/md5.h000066400000000000000000000073051273231111400217060ustar00rootroot00000000000000/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* NOTE: Per restriction 2 above, this file has been altered by MongoDB as follows: 1. The functions md5_init, md5_append, and md5_finish have been moved into the 'mongo' namespace and given C++ linkage, so that static archives of this library may be combined with other libraries that expose functions of the same name. */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED #define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ // Don't do this. Turns out its actually slower... // #define ARCH_IS_BIG_ENDIAN 0 typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; namespace mongo { /* Initialize the algorithm. */ void md5_init(md5_state_t* pms); /* Append a string to the message. */ void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t* pms, md5_byte_t digest[16]); } // namespace mongo #endif /* md5_INCLUDED */ mongo-cxx-driver-legacy-1.1.2/src/mongo/util/md5.hpp000066400000000000000000000033371273231111400222470ustar00rootroot00000000000000// md5.hpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/util/md5.h" #include #include #include namespace mongo { typedef unsigned char md5digest[16]; inline void md5(const void *buf, int nbytes, md5digest digest) { md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t *) buf, nbytes); md5_finish(&st, digest); } inline void md5(const char *str, md5digest digest) { md5(str, strlen(str), digest); } inline std::string digestToString( md5digest digest ){ static const char * letters = "0123456789abcdef"; std::stringstream ss; for ( int i=0; i<16; i++){ unsigned char c = digest[i]; ss << letters[ ( c >> 4 ) & 0xf ] << letters[ c & 0xf ]; } return ss.str(); } inline std::string md5simpledigest( const void* buf, int nbytes){ md5digest d; md5( buf, nbytes , d ); return digestToString( d ); } inline std::string md5simpledigest( const std::string& s ){ return md5simpledigest(s.data(), s.size()); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/mongoutils/000077500000000000000000000000001273231111400232435ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/util/mongoutils/str.h000066400000000000000000000156461273231111400242400ustar00rootroot00000000000000// @file str.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once /** * String utilities. * * TODO: De-inline. * TODO: Retire the mongoutils namespace, and move str under the mongo namespace. */ #include #include #include "mongo/bson/util/builder.h" namespace mongoutils { namespace str { /** the idea here is to make one liners easy. e.g.: return str::stream() << 1 << ' ' << 2; since the following doesn't work: (stringstream() << 1).str(); */ class stream { public: mongo::StringBuilder ss; template stream& operator<<(const T& v) { ss << v; return *this; } operator std::string() const { return ss.str(); } }; inline bool startsWith(const char* str, const char* prefix) { const char* s = str; const char* p = prefix; while (*p) { if (*p != *s) return false; p++; s++; } return true; } inline bool startsWith(const std::string& s, const std::string& p) { return startsWith(s.c_str(), p.c_str()); } // while these are trivial today use in case we do different wide char things later inline bool startsWith(const char* p, char ch) { return *p == ch; } inline bool startsWith(const std::string& s, char ch) { return startsWith(s.c_str(), ch); } inline bool endsWith(const std::string& s, const std::string& p) { int l = p.size(); int x = s.size(); if (x < l) return false; return strncmp(s.c_str() + x - l, p.c_str(), l) == 0; } inline bool endsWith(const char* s, char p) { size_t len = strlen(s); return len && s[len - 1] == p; } inline bool endsWith(const char* p, const char* suffix) { size_t a = strlen(p); size_t b = strlen(suffix); if (b > a) return false; return strcmp(p + a - b, suffix) == 0; } inline bool equals(const char* a, const char* b) { return strcmp(a, b) == 0; } /** find char x, and return rest of string thereafter, or "" if not found */ inline const char* after(const char* s, char x) { const char* p = strchr(s, x); return (p != 0) ? p + 1 : ""; } inline std::string after(const std::string& s, char x) { const char* p = strchr(s.c_str(), x); return (p != 0) ? std::string(p + 1) : ""; } /** find string x, and return rest of string thereafter, or "" if not found */ inline const char* after(const char* s, const char* x) { const char* p = strstr(s, x); return (p != 0) ? p + strlen(x) : ""; } inline std::string after(const std::string& s, const std::string& x) { const char* p = strstr(s.c_str(), x.c_str()); return (p != 0) ? std::string(p + x.size()) : ""; } /** @return true if s contains x * These should not be used with strings containing NUL bytes */ inline bool contains(const std::string& s, const std::string& x) { return strstr(s.c_str(), x.c_str()) != 0; } inline bool contains(const std::string& s, char x) { verify(x != '\0'); // this expects c-strings so don't use when looking for NUL bytes return strchr(s.c_str(), x) != 0; } /** @return everything before the character x, else entire string */ inline std::string before(const std::string& s, char x) { const char* p = strchr(s.c_str(), x); return (p != 0) ? s.substr(0, p - s.c_str()) : s; } /** @return everything before the string x, else entire string */ inline std::string before(const std::string& s, const std::string& x) { const char* p = strstr(s.c_str(), x.c_str()); return (p != 0) ? s.substr(0, p - s.c_str()) : s; } /** check if if strings share a common starting prefix @return offset of divergence (or length if equal). 0=nothing in common. */ inline int shareCommonPrefix(const char* p, const char* q) { int ofs = 0; while (1) { if (*p == 0 || *q == 0) break; if (*p != *q) break; p++; q++; ofs++; } return ofs; } inline int shareCommonPrefix(const std::string& a, const std::string& b) { return shareCommonPrefix(a.c_str(), b.c_str()); } /** string to unsigned. zero if not a number. can end with non-num chars */ inline unsigned toUnsigned(const std::string& a) { unsigned x = 0; const char* p = a.c_str(); while (1) { if (!isdigit(*p)) break; x = x * 10 + (*p - '0'); p++; } return x; } /** split a string on a specific char. We don't split N times, just once on the first occurrence. If char not present entire string is in L and R is empty. @return true if char found */ inline bool splitOn(const std::string& s, char c, std::string& L, std::string& R) { const char* start = s.c_str(); const char* p = strchr(start, c); if (p == 0) { L = s; R.clear(); return false; } L = std::string(start, p - start); R = std::string(p + 1); return true; } /** split scanning reverse direction. Splits ONCE ONLY. */ inline bool rSplitOn(const std::string& s, char c, std::string& L, std::string& R) { const char* start = s.c_str(); const char* p = strrchr(start, c); if (p == 0) { L = s; R.clear(); return false; } L = std::string(start, p - start); R = std::string(p + 1); return true; } /** @return number of occurrences of c in s */ inline unsigned count(const std::string& s, char c) { unsigned n = 0; for (unsigned i = 0; i < s.size(); i++) if (s[i] == c) n++; return n; } /** trim leading spaces. spaces only, not tabs etc. */ inline std::string ltrim(const std::string& s) { const char* p = s.c_str(); while (*p == ' ') p++; return p; } /** remove trailing chars in place */ inline void stripTrailing(std::string& s, const char* chars) { std::string::iterator to = s.begin(); for (std::string::iterator i = s.begin(); i != s.end(); i++) { // During each iteration if i finds a non-"chars" character it writes it to the // position of t. So the part of the string left from the "to" iterator is already // "cleared" string. if (!contains(chars, *i)) { if (i != to) s.replace(to, to + 1, 1, *i); to++; } } s.erase(to, s.end()); } } // namespace str } // namespace mongoutils namespace mongo { using namespace mongoutils; #if defined(_WIN32) inline int strcasecmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/mongoutils/str_test.cpp000066400000000000000000000035671273231111400256310ustar00rootroot00000000000000// str_test.cpp /* Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/unittest/unittest.h" #include "mongo/util/mongoutils/str.h" namespace { namespace str = mongoutils::str; TEST(StripTrailingTests, RemoveFromHead) { std::string data("remove from head"); str::stripTrailing(data, "re"); ASSERT_EQUALS("mov fom had", data); } TEST(StripTrailingTests, RemoveFromTail) { std::string data("remove from tail"); str::stripTrailing(data, "ail"); ASSERT_EQUALS("remove from t", data); } TEST(StripTrailingTests, RemoveSpaces) { std::string data("remove spaces"); str::stripTrailing(data, " a"); ASSERT_EQUALS("removespces", data); } TEST(StripTrailingTests, RemoveFromMiddle) { std::string data("remove from middle"); str::stripTrailing(data, "from"); ASSERT_EQUALS("eve iddle", data); } TEST(StripTrailingTests, RemoveFromEmpty) { std::string data(""); str::stripTrailing(data, "from"); ASSERT_EQUALS("", data); } TEST(StripTrailingTests, RemoveEmpty) { std::string data("remove empty"); str::stripTrailing(data, ""); ASSERT_EQUALS("remove empty", data); } TEST(StripTrailingTests, RemoveBringsEmptyResult) { std::string data("remove"); str::stripTrailing(data, "remove"); ASSERT_EQUALS("", data); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/000077500000000000000000000000001273231111400216315ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/hostandport.cpp000066400000000000000000000134521273231111400247070ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/net/hostandport.h" #include #include "mongo/base/parse_number.h" #include "mongo/base/status.h" #include "mongo/base/status_with.h" #include "mongo/base/string_data.h" #include "mongo/bson/util/builder.h" #include "mongo/client/options.h" #include "mongo/db/jsobj.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/sock.h" #include "mongo/util/assert_util.h" namespace mongo { StatusWith HostAndPort::parse(const StringData& text) { HostAndPort result; Status status = result.initialize(text); if (!status.isOK()) { return StatusWith(status); } return StatusWith(result); } HostAndPort::HostAndPort() : _port(-1) {} HostAndPort::HostAndPort(const StringData& text) { uassertStatusOK(initialize(text)); } HostAndPort::HostAndPort(const std::string& h, int p) : _host(h), _port(p) {} bool HostAndPort::operator<(const HostAndPort& r) const { const int cmp = host().compare(r.host()); if (cmp) return cmp < 0; return port() < r.port(); } bool HostAndPort::operator==(const HostAndPort& r) const { return host() == r.host() && port() == r.port(); } int HostAndPort::port() const { if (hasPort()) return _port; return client::Options::kDbServer; } bool HostAndPort::isLocalHost() const { return (_host == "localhost" || str::startsWith(_host.c_str(), "127.") || _host == "::1" || _host == "anonymous unix socket" || _host.c_str()[0] == '/' // unix socket ); } std::string HostAndPort::toString() const { StringBuilder ss; append(ss); return ss.str(); } void HostAndPort::append(StringBuilder& ss) const { // wrap ipv6 addresses in []s for roundtrip-ability if (host().find(':') != std::string::npos) { ss << '[' << host() << ']'; } else { ss << host(); } ss << ':' << port(); } bool HostAndPort::empty() const { return _host.empty() && _port < 0; } Status HostAndPort::initialize(const StringData& s) { size_t colonPos = s.rfind(':'); StringData hostPart = s.substr(0, colonPos); // handle ipv6 hostPart (which we require to be wrapped in []s) const size_t openBracketPos = s.find('['); const size_t closeBracketPos = s.find(']'); if (openBracketPos != std::string::npos) { if (openBracketPos != 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "'[' present, but not first character in " << s.toString()); } if (closeBracketPos == std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "ipv6 address is missing closing ']' in hostname in " << s.toString()); } hostPart = s.substr(openBracketPos + 1, closeBracketPos - openBracketPos - 1); // prevent accidental assignment of port to the value of the final portion of hostPart if (colonPos < closeBracketPos) { colonPos = std::string::npos; } else if (colonPos != closeBracketPos + 1) { return Status(ErrorCodes::FailedToParse, str::stream() << "Extraneous characters between ']' and pre-port ':'" << " in " << s.toString()); } } else if (closeBracketPos != std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "']' present without '[' in " << s.toString()); } else if (s.find(':') != colonPos) { return Status(ErrorCodes::FailedToParse, str::stream() << "More than one ':' detected. If this is an ipv6 address," << " it needs to be surrounded by '[' and ']'; " << s.toString()); } if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); } std::ostream& operator<<(std::ostream& os, const HostAndPort& hp) { return os << hp.toString(); } } // namespace mongo MONGO_HASH_NAMESPACE_START size_t hash::operator()(const mongo::HostAndPort& host) const { hash intHasher; size_t hash = intHasher(host.port()); boost::hash_combine(hash, host.host()); return hash; } MONGO_HASH_NAMESPACE_END mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/hostandport.h000066400000000000000000000065771273231111400243660ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/bson/util/builder.h" #include "mongo/platform/hash_namespace.h" namespace mongo { class Status; class StringData; template class StatusWith; /** * Name of a process on the network. * * Composed of some name component, followed optionally by a colon and a numeric port. The name * might be an IPv4 or IPv6 address or a relative or fully qualified host name, or an absolute * path to a unix socket. */ struct MONGO_CLIENT_API HostAndPort { /** * Parses "text" to produce a HostAndPort. Returns either that or an error * status describing the parse failure. */ static StatusWith MONGO_CLIENT_FUNC parse(const StringData& text); /** * Construct an empty/invalid HostAndPort. */ HostAndPort(); /** * Constructs a HostAndPort by parsing "text" of the form hostname[:portnumber] * Throws an AssertionException if bad config std::string or bad port #. */ explicit HostAndPort(const StringData& text); /** * Constructs a HostAndPort with the hostname "h" and port "p". * * If "p" is -1, port() returns ServerGlobalParams::DefaultDBPort. */ HostAndPort(const std::string& h, int p); /** * (Re-)initializes this HostAndPort by parsing "s". Returns * Status::OK on success. The state of this HostAndPort is unspecified * after initialize() returns a non-OK status, though it is safe to * assign to it or re-initialize it. */ Status initialize(const StringData& s); bool operator<(const HostAndPort& r) const; bool operator==(const HostAndPort& r) const; bool operator!=(const HostAndPort& r) const { return !(*this == r); } /** * Returns true if the hostname looks localhost-y. * * TODO: Make a more rigorous implementation, perhaps elsewhere in * the networking library. */ bool isLocalHost() const; /** * Returns a string representation of "host:port". */ std::string toString() const; /** * Like toString(), above, but writes to "ss", instead. */ void append(StringBuilder& ss) const; /** * Returns true if this object represents no valid HostAndPort. */ bool empty() const; const std::string& host() const { return _host; } int port() const; bool hasPort() const { return _port >= 0; } private: std::string _host; int _port; // -1 indicates unspecified }; MONGO_CLIENT_API std::ostream& MONGO_CLIENT_FUNC operator<<(std::ostream& os, const HostAndPort& hp); } // namespace mongo MONGO_HASH_NAMESPACE_START template <> struct hash { size_t operator()(const mongo::HostAndPort& host) const; }; MONGO_HASH_NAMESPACE_END mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/hostandport_test.cpp000066400000000000000000000112501273231111400257400ustar00rootroot00000000000000/* Copyright 2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/net/hostandport.h" #include "mongo/client/options.h" #include "mongo/unittest/unittest.h" #include "mongo/util/assert_util.h" namespace mongo { namespace { TEST(HostAndPort, BasicLessThanComparison) { // Not less than self. ASSERT_FALSE(HostAndPort("a", 1) < HostAndPort("a", 1)); // Lex order by name. ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("b", 1)); ASSERT_FALSE(HostAndPort("b", 1) < HostAndPort("a", 1)); // Then, order by port number. ASSERT_LESS_THAN(HostAndPort("a", 1), HostAndPort("a", 2)); ASSERT_FALSE(HostAndPort("a", 2) < HostAndPort("a", 1)); } TEST(HostAndPort, BasicEquality) { // Comparison on host field ASSERT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 1)); ASSERT_FALSE(HostAndPort("b", 1) == HostAndPort("a", 1)); ASSERT_FALSE(HostAndPort("a", 1) != HostAndPort("a", 1)); ASSERT_NOT_EQUALS(HostAndPort("b", 1), HostAndPort("a", 1)); // Comparison on port field ASSERT_FALSE(HostAndPort("a", 1) == HostAndPort("a", 2)); ASSERT_NOT_EQUALS(HostAndPort("a", 1), HostAndPort("a", 2)); } TEST(HostAndPort, ImplicitPortSelection) { ASSERT_EQUALS(HostAndPort("a", -1), HostAndPort("a", int(client::Options::kDbServer))); ASSERT_EQUALS(int(client::Options::kDbServer), HostAndPort("a", -1).port()); ASSERT_FALSE(HostAndPort("a", -1).empty()); } TEST(HostAndPort, ConstructorParsing) { ASSERT_THROWS(HostAndPort(""), AssertionException); ASSERT_THROWS(HostAndPort("a:"), AssertionException); ASSERT_THROWS(HostAndPort("a:0xa"), AssertionException); ASSERT_THROWS(HostAndPort(":123"), AssertionException); ASSERT_THROWS(HostAndPort("[124d:"), AssertionException); ASSERT_THROWS(HostAndPort("[124d:]asdf:34"), AssertionException); ASSERT_THROWS(HostAndPort("frim[124d:]:34"), AssertionException); ASSERT_THROWS(HostAndPort("[124d:]12:34"), AssertionException); ASSERT_THROWS(HostAndPort("124d:12:34"), AssertionException); ASSERT_EQUALS(HostAndPort("abc"), HostAndPort("abc", -1)); ASSERT_EQUALS(HostAndPort("abc.def:3421"), HostAndPort("abc.def", 3421)); ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort("124d:", 34)); ASSERT_EQUALS(HostAndPort("[124d:efg]:34"), HostAndPort("124d:efg", 34)); ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort("124d:", -1)); } TEST(HostAndPort, StaticParseFunction) { ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("a:0xa").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse(":123").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[124d:]asdf:34").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("124d:asdf:34").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("1234:").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]]").getStatus()); ASSERT_EQUALS(ErrorCodes::FailedToParse, HostAndPort::parse("[[124d]:34]").getStatus()); ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc")), HostAndPort("abc", -1)); ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("abc.def:3421")), HostAndPort("abc.def", 3421)); ASSERT_EQUALS(unittest::assertGet(HostAndPort::parse("[243:1bc]:21")), HostAndPort("243:1bc", 21)); } TEST(HostAndPort, RoundTripAbility) { ASSERT_EQUALS(HostAndPort("abc"), HostAndPort(HostAndPort("abc").toString())); ASSERT_EQUALS(HostAndPort("abc.def:3421"), HostAndPort(HostAndPort("abc.def:3421").toString())); ASSERT_EQUALS(HostAndPort("[124d:]:34"), HostAndPort(HostAndPort("[124d:]:34").toString())); ASSERT_EQUALS(HostAndPort("[124d:]"), HostAndPort(HostAndPort("[124d:]").toString())); } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/message.cpp000066400000000000000000000026301273231111400237620ustar00rootroot00000000000000// message.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/net/message.h" #include #include #include #include "mongo/util/net/message_port.h" namespace mongo { void Message::send(MessagingPort& p, const char* context) { if (empty()) { return; } if (_buf != 0) { p.send(_buf, MsgData::ConstView(_buf).getLen(), context); } else { p.send(_data, context); } } AtomicWord NextMsgId; /*struct MsgStart { MsgStart() { NextMsgId = (((unsigned) time(0)) << 16) ^ curTimeMillis(); verify(MsgDataHeaderSize == 16); } } msgstart;*/ MSGID nextMessageId() { return NextMsgId.fetchAndAdd(1); } bool doesOpGetAResponse(int op) { return op == dbQuery || op == dbGetMore; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/message.h000066400000000000000000000266731273231111400234440ustar00rootroot00000000000000// message.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/platform/atomic_word.h" #include "mongo/platform/cstdint.h" #include "mongo/base/data_view.h" #include "mongo/base/encoded_value_storage.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/net/operation.h" #include "mongo/util/net/sock.h" namespace mongo { /** * Maximum accepted message size on the wire protocol. */ const size_t MaxMessageSizeBytes = 48 * 1000 * 1000; class Message; class MessagingPort; class PiggyBackData; typedef uint32_t MSGID; bool doesOpGetAResponse(int op); inline const char* opToString(int op) { switch (op) { case 0: return "none"; case opReply: return "reply"; case dbMsg: return "msg"; case dbUpdate: return "update"; case dbInsert: return "insert"; case dbQuery: return "query"; case dbGetMore: return "getmore"; case dbDelete: return "remove"; case dbKillCursors: return "killcursors"; default: massert(16141, str::stream() << "cannot translate opcode " << op, !op); return ""; } } inline bool opIsWrite(int op) { switch (op) { case 0: case opReply: case dbMsg: case dbQuery: case dbGetMore: case dbKillCursors: return false; case dbUpdate: case dbInsert: case dbDelete: return true; default: verify(0); return ""; } } namespace MSGHEADER { #pragma pack(1) /* see http://dochub.mongodb.org/core/mongowireprotocol */ struct Layout { int32_t messageLength; // total message size, including this int32_t requestID; // identifier for this message int32_t responseTo; // requestID from the original request // (used in responses from db) int32_t opCode; }; #pragma pack() class ConstView { public: typedef ConstDataView view_type; ConstView(const char* data) : _data(data) {} const char* view2ptr() const { return data().view(); } int32_t getMessageLength() const { return data().readLE(offsetof(Layout, messageLength)); } int32_t getRequestID() const { return data().readLE(offsetof(Layout, requestID)); } int32_t getResponseTo() const { return data().readLE(offsetof(Layout, responseTo)); } int32_t getOpCode() const { return data().readLE(offsetof(Layout, opCode)); } protected: const view_type& data() const { return _data; } private: view_type _data; }; class View : public ConstView { public: typedef DataView view_type; View(char* data) : ConstView(data) {} using ConstView::view2ptr; char* view2ptr() { return data().view(); } void setMessageLength(int32_t value) { data().writeLE(value, offsetof(Layout, messageLength)); } void setRequestID(int32_t value) { data().writeLE(value, offsetof(Layout, requestID)); } void setResponseTo(int32_t value) { data().writeLE(value, offsetof(Layout, responseTo)); } void setOpCode(int32_t value) { data().writeLE(value, offsetof(Layout, opCode)); } private: view_type data() const { return const_cast(ConstView::view2ptr()); } }; class Value : public EncodedValueStorage { public: Value() { BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout)); } Value(ZeroInitTag_t zit) : EncodedValueStorage(zit) {} }; } // namespace MSGHEADER namespace MsgData { #pragma pack(1) struct Layout { MSGHEADER::Layout header; char data[4]; }; #pragma pack() class ConstView { public: ConstView(const char* storage) : _storage(storage) {} const char* view2ptr() const { return storage().view(); } int32_t getLen() const { return header().getMessageLength(); } MSGID getId() const { return header().getRequestID(); } MSGID getResponseTo() const { return header().getResponseTo(); } int32_t getOperation() const { return header().getOpCode(); } const char* data() const { return storage().view(offsetof(Layout, data)); } bool valid() const { if (getLen() <= 0 || getLen() > (4 * BSONObjMaxInternalSize)) return false; if (getOperation() < 0 || getOperation() > 30000) return false; return true; } int64_t getCursor() const { verify(getResponseTo() > 0); verify(getOperation() == opReply); return ConstDataView(data() + sizeof(int32_t)).readLE(); } int dataLen() const; // len without header protected: const ConstDataView& storage() const { return _storage; } MSGHEADER::ConstView header() const { return storage().view(offsetof(Layout, header)); } private: ConstDataView _storage; }; class View : public ConstView { public: View(char* storage) : ConstView(storage) {} using ConstView::view2ptr; char* view2ptr() { return storage().view(); } void setLen(int value) { return header().setMessageLength(value); } void setId(MSGID value) { return header().setRequestID(value); } void setResponseTo(MSGID value) { return header().setResponseTo(value); } void setOperation(int value) { return header().setOpCode(value); } using ConstView::data; char* data() { return storage().view(offsetof(Layout, data)); } private: DataView storage() const { return const_cast(ConstView::view2ptr()); } MSGHEADER::View header() const { return storage().view(offsetof(Layout, header)); } }; class Value : public EncodedValueStorage { public: Value() { BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout)); } Value(ZeroInitTag_t zit) : EncodedValueStorage(zit) {} }; const int MsgDataHeaderSize = sizeof(Value) - 4; inline int ConstView::dataLen() const { return getLen() - MsgDataHeaderSize; } } // namespace MsgData class Message { public: // we assume here that a vector with initial size 0 does no allocation (0 is the default, but // wanted to make it explicit). Message() : _buf(0), _data(0), _freeIt(false) {} Message(void* data, bool freeIt) : _buf(0), _data(0), _freeIt(false) { _setData(reinterpret_cast(data), freeIt); }; Message(Message& r) : _buf(0), _data(0), _freeIt(false) { *this = r; } ~Message() { reset(); } SockAddr _from; MsgData::View header() const { verify(!empty()); return _buf ? _buf : _data[0].first; } int operation() const { return header().getOperation(); } MsgData::View singleData() const { massert(13273, "single data buffer expected", _buf); return header(); } bool empty() const { return !_buf && _data.empty(); } int size() const { int res = 0; if (_buf) { res = MsgData::ConstView(_buf).getLen(); } else { for (MsgVec::const_iterator it = _data.begin(); it != _data.end(); ++it) { res += it->second; } } return res; } int dataSize() const { return size() - sizeof(MSGHEADER::Value); } // concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy // can get rid of this if we make response handling smarter void concat() { if (_buf || empty()) { return; } verify(_freeIt); int totalSize = 0; for (std::vector >::const_iterator i = _data.begin(); i != _data.end(); ++i) { totalSize += i->second; } char* buf = (char*)malloc(totalSize); char* p = buf; for (std::vector >::const_iterator i = _data.begin(); i != _data.end(); ++i) { memcpy(p, i->first, i->second); p += i->second; } reset(); _setData(buf, true); } // vector swap() so this is fast Message& operator=(Message& r) { verify(empty()); verify(r._freeIt); _buf = r._buf; r._buf = 0; if (r._data.size() > 0) { _data.swap(r._data); } r._freeIt = false; _freeIt = true; return *this; } void reset() { if (_freeIt) { if (_buf) { free(_buf); } for (std::vector >::const_iterator i = _data.begin(); i != _data.end(); ++i) { free(i->first); } } _buf = 0; _data.clear(); _freeIt = false; } // use to add a buffer // assumes message will free everything void appendData(char* d, int size) { if (size <= 0) { return; } if (empty()) { MsgData::View md = d; md.setLen(size); // can be updated later if more buffers added _setData(md.view2ptr(), true); return; } verify(_freeIt); if (_buf) { _data.push_back(std::make_pair(_buf, MsgData::ConstView(_buf).getLen())); _buf = 0; } _data.push_back(std::make_pair(d, size)); header().setLen(header().getLen() + size); } // use to set first buffer if empty void setData(char* d, bool freeIt) { verify(empty()); _setData(d, freeIt); } void setData(int operation, const char* msgtxt) { setData(operation, msgtxt, strlen(msgtxt) + 1); } void setData(int operation, const char* msgdata, size_t len) { verify(empty()); size_t dataLen = len + sizeof(MsgData::Value) - 4; MsgData::View d = reinterpret_cast(malloc(dataLen)); memcpy(d.data(), msgdata, len); d.setLen(dataLen); d.setOperation(operation); _setData(d.view2ptr(), true); } bool doIFreeIt() { return _freeIt; } void send(MessagingPort& p, const char* context); std::string toString() const; private: void _setData(char* d, bool freeIt) { _freeIt = freeIt; _buf = d; } // if just one buffer, keep it in _buf, otherwise keep a sequence of buffers in _data char* _buf; // byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage // instead typedef std::vector > MsgVec; MsgVec _data; bool _freeIt; }; MSGID nextMessageId(); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/message_port.cpp000066400000000000000000000240431273231111400250300ustar00rootroot00000000000000// message_port.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/util/net/message_port.h" #include #include #include #include #include #include "mongo/client/options.h" #include "mongo/util/background.h" #include "mongo/util/log.h" #include "mongo/util/net/message.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/scopeguard.h" #include "mongo/util/time_support.h" #ifndef _WIN32 #ifndef __sunos__ #include #endif #include #include #endif namespace mongo { using std::dec; using std::endl; using std::hex; using std::set; using std::string; using std::stringstream; // if you want trace output: #define mmm(x) void AbstractMessagingPort::setConnectionId(long long connectionId) { verify(_connectionId == 0); _connectionId = connectionId; } /* messagingport -------------------------------------------------------------- */ class PiggyBackData { public: PiggyBackData(MessagingPort* port) { _port = port; _buf = new char[1300]; _cur = _buf; } ~PiggyBackData() { DESTRUCTOR_GUARD(flush(); delete[](_cur);); } void append(Message& m) { verify(m.header().getLen() <= 1300); if (len() + m.header().getLen() > 1300) flush(); memcpy(_cur, m.singleData().view2ptr(), m.header().getLen()); _cur += m.header().getLen(); } void flush() { if (_buf == _cur) return; _port->send(_buf, len(), "flush"); _cur = _buf; } int len() const { return _cur - _buf; } private: MessagingPort* _port; char* _buf; char* _cur; }; class Ports { std::set ports; boost::mutex m; public: Ports() : ports(), m() {} void closeAll(unsigned skip_mask) { boost::lock_guard bl(m); for (set::iterator i = ports.begin(); i != ports.end(); i++) { if ((*i)->tag & skip_mask) continue; (*i)->shutdown(); } } void insert(MessagingPort* p) { boost::lock_guard bl(m); ports.insert(p); } void erase(MessagingPort* p) { boost::lock_guard bl(m); ports.erase(p); } }; // we "new" this so it is still be around when other automatic global vars // are being destructed during termination. Ports& ports = *(new Ports()); void MessagingPort::closeAllSockets(unsigned mask) { ports.closeAll(mask); } MessagingPort::MessagingPort(int fd, const SockAddr& remote) : psock(new Socket(fd, remote)), piggyBackData(0) { ports.insert(this); } MessagingPort::MessagingPort(double timeout, logger::LogSeverity ll) : psock(new Socket(timeout, ll)) { ports.insert(this); piggyBackData = 0; } MessagingPort::MessagingPort(boost::shared_ptr sock) : psock(sock), piggyBackData(0) { ports.insert(this); } void MessagingPort::setSocketTimeout(double timeout) { psock->setTimeout(timeout); } void MessagingPort::shutdown() { psock->close(); } MessagingPort::~MessagingPort() { if (piggyBackData) delete (piggyBackData); shutdown(); ports.erase(this); } bool MessagingPort::recv(Message& m) { try { #ifdef MONGO_SSL again: #endif // mmm( log() << "* recv() sock:" << this->sock << endl; ) MSGHEADER::Value header; int headerLen = sizeof(MSGHEADER::Value); psock->recv((char*)&header, headerLen); int len = header.constView().getMessageLength(); if (len == 542393671) { // an http GET string msg = "It looks like you are trying to access MongoDB over HTTP on the native driver " "port.\n"; LOG(psock->getLogLevel()) << msg; std::stringstream ss; ss << "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: " "text/plain\r\nContent-Length: " << msg.size() << "\r\n\r\n" << msg; string s = ss.str(); send(s.c_str(), s.size(), "http"); return false; } // If responseTo is not 0 or -1 for first packet assume SSL else if (psock->isAwaitingHandshake()) { #ifndef MONGO_SSL if (header.constView().getResponseTo() != 0 && header.constView().getResponseTo() != -1) { uasserted(17133, "SSL handshake requested, SSL feature not available in this build"); } #else if (header.constView().getResponseTo() != 0 && header.constView().getResponseTo() != -1) { uassert(17132, "SSL handshake received but initialized without SSL support", client::Options::current().SSLEnabled()); setX509SubjectName( psock->doSSLHandshake(reinterpret_cast(&header), sizeof(header))); psock->setHandshakeReceived(); goto again; } uassert(17189, "The client is configured to only allow SSL connections", client::Options::current().SSLMode() != client::Options::kSSLRequired); #endif // MONGO_SSL } if (static_cast(len) < sizeof(MSGHEADER::Value) || static_cast(len) > MaxMessageSizeBytes) { LOG(0) << "recv(): message len " << len << " is invalid. " << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes; return false; } psock->setHandshakeReceived(); int z = (len + 1023) & 0xfffffc00; verify(z >= len); MsgData::View md = reinterpret_cast(malloc(z)); ScopeGuard guard = MakeGuard(free, md.view2ptr()); verify(md.view2ptr()); memcpy(md.view2ptr(), &header, headerLen); int left = len - headerLen; psock->recv(md.data(), left); guard.Dismiss(); m.setData(md.view2ptr(), true); return true; } catch (const SocketException& e) { logger::LogSeverity severity = psock->getLogLevel(); if (!e.shouldPrint()) severity = severity.lessSevere(); LOG(severity) << "SocketException: remote: " << remote() << " error: " << e; m.reset(); return false; } } void MessagingPort::reply(Message& received, Message& response) { say(/*received.from, */ response, received.header().getId()); } void MessagingPort::reply(Message& received, Message& response, MSGID responseTo) { say(/*received.from, */ response, responseTo); } bool MessagingPort::call(Message& toSend, Message& response) { mmm(log() << "*call()" << endl;) say(toSend); return recv(toSend, response); } bool MessagingPort::recv(const Message& toSend, Message& response) { while (1) { bool ok = recv(response); if (!ok) { mmm(log() << "recv not ok" << endl;) return false; } // log() << "got response: " << response.data->responseTo << endl; if (response.header().getResponseTo() == toSend.header().getId()) break; error() << "MessagingPort::call() wrong id got:" << std::hex << (unsigned)response.header().getResponseTo() << " expect:" << (unsigned)toSend.header().getId() << '\n' << std::dec << " toSend op: " << (unsigned)toSend.operation() << '\n' << " response msgid:" << (unsigned)response.header().getId() << '\n' << " response len: " << (unsigned)response.header().getLen() << '\n' << " response op: " << response.operation() << '\n' << " remote: " << psock->remoteString(); verify(false); response.reset(); } mmm(log() << "*call() end" << endl;) return true; } void MessagingPort::say(Message& toSend, int responseTo) { verify(!toSend.empty()); mmm(log() << "* say() thr:" << GetCurrentThreadId() << endl;) toSend.header().setId(nextMessageId()); toSend.header().setResponseTo(responseTo); if (piggyBackData && piggyBackData->len()) { mmm(log() << "* have piggy back" << endl;) if ((piggyBackData->len() + toSend.header().getLen()) > 1300) { // won't fit in a packet - so just send it off piggyBackData->flush(); } else { piggyBackData->append(toSend); piggyBackData->flush(); return; } } toSend.send(*this, "say"); } void MessagingPort::piggyBack(Message& toSend, int responseTo) { if (toSend.header().getLen() > 1300) { // not worth saving because its almost an entire packet say(toSend); return; } // we're going to be storing this, so need to set it up toSend.header().setId(nextMessageId()); toSend.header().setResponseTo(responseTo); if (!piggyBackData) piggyBackData = new PiggyBackData(this); piggyBackData->append(toSend); } HostAndPort MessagingPort::remote() const { if (!_remoteParsed.hasPort()) { SockAddr sa = psock->remoteAddr(); _remoteParsed = HostAndPort(sa.getAddr(), sa.getPort()); } return _remoteParsed; } SockAddr MessagingPort::remoteAddr() const { return psock->remoteAddr(); } SockAddr MessagingPort::localAddr() const { return psock->localAddr(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/message_port.h000066400000000000000000000116001273231111400244700ustar00rootroot00000000000000// message_port.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #include #include #include #include "mongo/util/net/message.h" #include "mongo/util/net/sock.h" namespace mongo { class MessagingPort; class PiggyBackData; class AbstractMessagingPort : boost::noncopyable { public: AbstractMessagingPort() : tag(0), _connectionId(0) {} virtual ~AbstractMessagingPort() {} virtual void reply( Message& received, Message& response, // like the reply below, but doesn't rely on received.data still being available MSGID responseTo) = 0; virtual void reply(Message& received, Message& response) = 0; virtual HostAndPort remote() const = 0; virtual unsigned remotePort() const = 0; virtual SockAddr remoteAddr() const = 0; virtual SockAddr localAddr() const = 0; void setX509SubjectName(const std::string& x509SubjectName) { _x509SubjectName = x509SubjectName; } std::string getX509SubjectName() { return _x509SubjectName; } long long connectionId() const { return _connectionId; } void setConnectionId(long long connectionId); public: // TODO make this private with some helpers /* ports can be tagged with various classes. see closeAllSockets(tag). defaults to 0. */ unsigned tag; private: long long _connectionId; std::string _x509SubjectName; }; class MessagingPort : public AbstractMessagingPort { public: MessagingPort(int fd, const SockAddr& remote); // in some cases the timeout will actually be 2x this value - eg we do a partial send, // then the timeout fires, then we try to send again, then the timeout fires again with // no data sent, then we detect that the other side is down MessagingPort(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log()); MessagingPort(boost::shared_ptr socket); virtual ~MessagingPort(); void setSocketTimeout(double timeout); void shutdown(); /* it's assumed if you reuse a message object, that it doesn't cross MessagingPort's. also, the Message data will go out of scope on the subsequent recv call. */ bool recv(Message& m); void reply(Message& received, Message& response, MSGID responseTo); void reply(Message& received, Message& response); bool call(Message& toSend, Message& response); void say(Message& toSend, int responseTo = 0); /** * this is used for doing 'async' queries * instead of doing call( to , from ) * you would do * say( to ) * recv( from ) * Note: if you fail to call recv and someone else uses this port, * horrible things will happen */ bool recv(const Message& sent, Message& response); void piggyBack(Message& toSend, int responseTo = 0); unsigned remotePort() const { return psock->remotePort(); } virtual HostAndPort remote() const; virtual SockAddr remoteAddr() const; virtual SockAddr localAddr() const; boost::shared_ptr psock; void send(const char* data, int len, const char* context) { psock->send(data, len, context); } void send(const std::vector >& data, const char* context) { psock->send(data, context); } bool connect(SockAddr& farEnd) { return psock->connect(farEnd); } #ifdef MONGO_SSL /** * Initiates the TLS/SSL handshake on this MessagingPort. * When this function returns, further communication on this * MessagingPort will be encrypted. * ssl - Pointer to the global SSLManager. * remoteHost - The hostname of the remote server. */ bool secure(SSLManagerInterface* ssl, const std::string& remoteHost) { return psock->secure(ssl, remoteHost); } #endif bool isStillConnected() { return psock->isStillConnected(); } uint64_t getSockCreationMicroSec() const { return psock->getSockCreationMicroSec(); } private: PiggyBackData* piggyBackData; // this is the parsed version of remote // mutable because its initialized only on call to remote() mutable HostAndPort _remoteParsed; public: static void closeAllSockets(unsigned tagMask = 0xffffffff); friend class PiggyBackData; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/operation.h000066400000000000000000000021061273231111400240010ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once namespace mongo { enum Operations { opReply = 1, /* reply. responseTo is set. */ dbMsg = 1000, /* generic msg command followed by a string */ dbUpdate = 2001, /* update object */ dbInsert = 2002, // dbGetByOID = 2003, dbQuery = 2004, dbGetMore = 2005, dbDelete = 2006, dbKillCursors = 2007 }; enum WriteOpType { dbWriteUpdate = dbUpdate, dbWriteInsert = dbInsert, dbWriteDelete = dbDelete }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/sock.cpp000066400000000000000000000707041273231111400233040ustar00rootroot00000000000000// @file sock.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/util/net/sock.h" #if !defined(_WIN32) #include #include #include #include #include #include #include #include #if defined(__openbsd__) #include #endif #endif #include "mongo/client/private/options.h" #include "mongo/util/background.h" #include "mongo/util/debug_util.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/log.h" #include "mongo/util/net/message.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/net/socket_poll.h" namespace mongo { using std::endl; using std::pair; using std::string; using std::stringstream; using std::vector; MONGO_FP_DECLARE(throwSockExcep); MONGO_FP_DECLARE(notStillConnected); static bool ipv6 = false; void enableIPv6(bool state) { ipv6 = state; } bool IPv6Enabled() { return ipv6; } void setSockTimeouts(int sock, double secs) { bool report = shouldLog(logger::LogSeverity::Debug(4)); DEV report = true; #if defined(_WIN32) DWORD timeout = secs * 1000; // Windows timeout is a DWORD, in milliseconds. int status = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeout), sizeof(DWORD)); if (report && (status == SOCKET_ERROR)) log() << "unable to set SO_RCVTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl; status = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast(&timeout), sizeof(DWORD)); DEV if (report && (status == SOCKET_ERROR)) log() << "unable to set SO_SNDTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl; #else struct timeval tv; tv.tv_sec = (int)secs; tv.tv_usec = (int)((long long)(secs * 1000 * 1000) % (1000 * 1000)); bool ok = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == 0; if (report && !ok) log() << "unable to set SO_RCVTIMEO" << endl; ok = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)) == 0; DEV if (report && !ok) log() << "unable to set SO_SNDTIMEO" << endl; #endif } #if defined(_WIN32) void disableNagle(int sock) { int x = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&x, sizeof(x))) error() << "disableNagle failed: " << errnoWithDescription() << endl; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x))) error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl; } #else void disableNagle(int sock) { int x = 1; #ifdef SOL_TCP int level = SOL_TCP; #else int level = SOL_SOCKET; #endif if (setsockopt(sock, level, TCP_NODELAY, (char*)&x, sizeof(x))) error() << "disableNagle failed: " << errnoWithDescription() << endl; #ifdef SO_KEEPALIVE if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x))) error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl; #ifdef __linux__ socklen_t len = sizeof(x); if (getsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, &len)) error() << "can't get TCP_KEEPIDLE: " << errnoWithDescription() << endl; if (x > 300) { x = 300; if (setsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, sizeof(x))) { error() << "can't set TCP_KEEPIDLE: " << errnoWithDescription() << endl; } } len = sizeof(x); // just in case it changed if (getsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, &len)) error() << "can't get TCP_KEEPINTVL: " << errnoWithDescription() << endl; if (x > 300) { x = 300; if (setsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, sizeof(x))) { error() << "can't set TCP_KEEPINTVL: " << errnoWithDescription() << endl; } } #endif #endif } #endif string getAddrInfoStrError(int code) { #if !defined(_WIN32) return gai_strerror(code); #else /* gai_strerrorA is not threadsafe on windows. don't use it. */ return errnoWithDescription(code); #endif } // --- SockAddr SockAddr::SockAddr() { addressSize = sizeof(sa); memset(&sa, 0, sizeof(sa)); sa.ss_family = AF_UNSPEC; _isValid = true; } SockAddr::SockAddr(int sourcePort) { memset(as().sin_zero, 0, sizeof(as().sin_zero)); as().sin_family = AF_INET; as().sin_port = htons(sourcePort); as().sin_addr.s_addr = htonl(INADDR_ANY); addressSize = sizeof(sockaddr_in); _isValid = true; } SockAddr::SockAddr(const char* _iporhost, int port) { string target = _iporhost; if (target == "localhost") { target = "127.0.0.1"; } if (mongoutils::str::contains(target, '/')) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert(13079, "path to unix socket too long", target.size() < sizeof(as().sun_path)); as().sun_family = AF_UNIX; strcpy(as().sun_path, target.c_str()); addressSize = sizeof(sockaddr_un); _isValid = true; return; } addrinfo* addrs = NULL; addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_socktype = SOCK_STREAM; // hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it. // SERVER-1579 hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); StringBuilder ss; ss << port; int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); // old C compilers on IPv6-capable hosts return EAI_NODATA error #ifdef EAI_NODATA int nodata = (ret == EAI_NODATA); #else int nodata = false; #endif if ((ret == EAI_NONAME || nodata)) { // iporhost isn't an IP address, allow DNS lookup hints.ai_flags &= ~AI_NUMERICHOST; ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); } if (ret) { // we were unsuccessful if (target != "0.0.0.0") { // don't log if this as it is a // CRT construction and log() may not work yet. log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret) << endl; _isValid = false; return; } *this = SockAddr(port); return; } // TODO: handle other addresses in linked list; fassert(16501, addrs->ai_addrlen <= sizeof(sa)); memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen); addressSize = addrs->ai_addrlen; freeaddrinfo(addrs); _isValid = true; } bool SockAddr::isLocalHost() const { switch (getType()) { case AF_INET: return getAddr() == "127.0.0.1"; case AF_INET6: return getAddr() == "::1"; case AF_UNIX: return true; default: return false; } fassert(16502, false); return false; } string SockAddr::toString(bool includePort) const { string out = getAddr(); if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC) out += mongoutils::str::stream() << ':' << getPort(); return out; } sa_family_t SockAddr::getType() const { return sa.ss_family; } unsigned SockAddr::getPort() const { switch (getType()) { case AF_INET: return ntohs(as().sin_port); case AF_INET6: return ntohs(as().sin6_port); case AF_UNIX: return 0; case AF_UNSPEC: return 0; default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return 0; } } std::string SockAddr::getAddr() const { switch (getType()) { case AF_INET: case AF_INET6: { const int buflen = 128; char buffer[buflen]; int ret = getnameinfo(raw(), addressSize, buffer, buflen, NULL, 0, NI_NUMERICHOST); massert(13082, mongoutils::str::stream() << "getnameinfo error " << getAddrInfoStrError(ret), ret == 0); return buffer; } case AF_UNIX: return (as().sun_path[0] != '\0' ? as().sun_path : "anonymous unix socket"); case AF_UNSPEC: return "(NONE)"; default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return ""; } } bool SockAddr::operator==(const SockAddr& r) const { if (getType() != r.getType()) return false; if (getPort() != r.getPort()) return false; switch (getType()) { case AF_INET: return as().sin_addr.s_addr == r.as().sin_addr.s_addr; case AF_INET6: return memcmp(as().sin6_addr.s6_addr, r.as().sin6_addr.s6_addr, sizeof(in6_addr)) == 0; case AF_UNIX: return strcmp(as().sun_path, r.as().sun_path) == 0; case AF_UNSPEC: return true; // assume all unspecified addresses are the same default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); } return false; } bool SockAddr::operator!=(const SockAddr& r) const { return !(*this == r); } bool SockAddr::operator<(const SockAddr& r) const { if (getType() < r.getType()) return true; else if (getType() > r.getType()) return false; if (getPort() < r.getPort()) return true; else if (getPort() > r.getPort()) return false; switch (getType()) { case AF_INET: return as().sin_addr.s_addr < r.as().sin_addr.s_addr; case AF_INET6: return memcmp(as().sin6_addr.s6_addr, r.as().sin6_addr.s6_addr, sizeof(in6_addr)) < 0; case AF_UNIX: return strcmp(as().sun_path, r.as().sun_path) < 0; case AF_UNSPEC: return false; default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); } return false; } SockAddr unknownAddress("0.0.0.0", 0); // If an ip address is passed in, just return that. If a hostname is passed // in, look up its ip and return that. Returns "" on failure. string hostbyname(const char* hostname) { SockAddr sockAddr(hostname, 0); if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0") return ""; else return sockAddr.getAddr(); } // --- my -- string getHostName() { char buf[256]; int ec = gethostname(buf, 127); if (ec || *buf == 0) { log() << "can't get this server's hostname " << errnoWithDescription() << endl; return ""; } return buf; } // --------- SocketException ---------- #ifdef MSG_NOSIGNAL const int portSendFlags = MSG_NOSIGNAL; const int portRecvFlags = MSG_NOSIGNAL; #else const int portSendFlags = 0; const int portRecvFlags = 0; #endif string SocketException::toString() const { stringstream ss; ss << _ei.code << " socket exception [" << _getStringType(_type) << "] "; if (_server.size()) ss << "server [" << _server << "] "; if (_extra.size()) ss << _extra; return ss.str(); } // ------------ Socket ----------------- static int socketGetLastError() { #ifdef _WIN32 return WSAGetLastError(); #else return errno; #endif } static SockAddr getLocalAddrForBoundSocketFd(int fd) { SockAddr result; int rc = getsockname(fd, result.raw(), &result.addressSize); if (rc != 0) { warning() << "Could not resolve local address for socket with fd " << fd << ": " << getAddrInfoStrError(socketGetLastError()); result = SockAddr(); } return result; } Socket::Socket(int fd, const SockAddr& remote) : _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)), _logLevel(logger::LogSeverity::Log()) { _init(); if (fd >= 0) { _local = getLocalAddrForBoundSocketFd(_fd); } } Socket::Socket(double timeout, logger::LogSeverity ll) : _logLevel(ll) { _fd = -1; _timeout = timeout; _lastValidityCheckAtSecs = time(0); _init(); } Socket::~Socket() { close(); } void Socket::_init() { _bytesOut = 0; _bytesIn = 0; _awaitingHandshake = true; #ifdef MONGO_SSL _sslManager = 0; #endif } void Socket::close() { if (_fd >= 0) { // Stop any blocking reads/writes, and prevent new reads/writes #if defined(_WIN32) shutdown(_fd, SD_BOTH); #else shutdown(_fd, SHUT_RDWR); #endif closesocket(_fd); _fd = -1; } } #ifdef MONGO_SSL bool Socket::secure(SSLManagerInterface* mgr, const std::string& remoteHost) { fassert(16503, mgr); if (_fd < 0) { return false; } _sslManager = mgr; _sslConnection.reset(_sslManager->connect(this)); mgr->parseAndValidatePeerCertificate(_sslConnection.get(), remoteHost); return true; } void Socket::secureAccepted(SSLManagerInterface* ssl) { _sslManager = ssl; } std::string Socket::doSSLHandshake(const char* firstBytes, int len) { if (!_sslManager) return ""; fassert(16506, _fd); if (_sslConnection.get()) { throw SocketException(SocketException::RECV_ERROR, "Attempt to call SSL_accept on already secure Socket from " + remoteString()); } _sslConnection.reset(_sslManager->accept(this, firstBytes, len)); return _sslManager->parseAndValidatePeerCertificate(_sslConnection.get(), ""); } #endif class ConnectBG : public BackgroundJob { public: ConnectBG(int sock, SockAddr remote) : _sock(sock), _remote(remote) {} void run() { #if defined(_WIN32) if ((_res = _connect()) == SOCKET_ERROR) { _errnoWithDescription = errnoWithDescription(); } #else while ((_res = _connect()) == -1) { const int error = errno; if (error != EINTR) { _errnoWithDescription = errnoWithDescription(error); break; } } #endif } std::string name() const { return "ConnectBG"; } std::string getErrnoWithDescription() const { return _errnoWithDescription; } int inError() const { return _res; } private: int _connect() const { return ::connect(_sock, _remote.raw(), _remote.addressSize); } int _sock; int _res; SockAddr _remote; std::string _errnoWithDescription; }; bool Socket::connect(SockAddr& remote) { _remote = remote; _fd = socket(remote.getType(), SOCK_STREAM, 0); if (_fd == INVALID_SOCKET) { LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl; return false; } if (_timeout > 0) { setTimeout(_timeout); } static const unsigned int connectTimeoutMillis = 5000; ConnectBG bg(_fd, remote); bg.go(); if (bg.wait(connectTimeoutMillis)) { if (bg.inError()) { warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << ", reason: " << bg.getErrnoWithDescription() << endl; close(); return false; } } else { // time out the connect close(); bg.wait(); // so bg stays in scope until bg thread terminates warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl; return false; } if (remote.getType() != AF_UNIX) disableNagle(_fd); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif _local = getLocalAddrForBoundSocketFd(_fd); _fdCreationMicroSec = curTimeMicros64(); _awaitingHandshake = false; return true; } // throws if SSL_write or send fails int Socket::_send(const char* data, int len, const char* context) { #ifdef MONGO_SSL if (_sslConnection.get()) { return _sslManager->SSL_write(_sslConnection.get(), data, len); } #endif int ret = ::send(_fd, data, len, portSendFlags); if (ret < 0) { handleSendError(ret, context); } return ret; } // sends all data or throws an exception void Socket::send(const char* data, int len, const char* context) { while (len > 0) { int ret = -1; if (MONGO_FAIL_POINT(throwSockExcep)) { #if defined(_WIN32) WSASetLastError(WSAENETUNREACH); #else errno = ENETUNREACH; #endif handleSendError(ret, context); } else { ret = _send(data, len, context); } _bytesOut += ret; fassert(16507, ret <= len); len -= ret; data += ret; } } void Socket::_send(const vector >& data, const char* context) { for (vector >::const_iterator i = data.begin(); i != data.end(); ++i) { char* data = i->first; int len = i->second; send(data, len, context); } } /** sends all data or throws an exception * @param context descriptive for logging */ void Socket::send(const vector >& data, const char* context) { #ifdef MONGO_SSL if (_sslConnection.get()) { _send(data, context); return; } #endif #if defined(_WIN32) // TODO use scatter/gather api _send(data, context); #else vector d(data.size()); int i = 0; for (vector >::const_iterator j = data.begin(); j != data.end(); ++j) { if (j->second > 0) { d[i].iov_base = j->first; d[i].iov_len = j->second; ++i; _bytesOut += j->second; } } struct msghdr meta; memset(&meta, 0, sizeof(meta)); meta.msg_iov = &d[0]; meta.msg_iovlen = d.size(); while (meta.msg_iovlen > 0) { int ret = -1; if (MONGO_FAIL_POINT(throwSockExcep)) { #if defined(_WIN32) WSASetLastError(WSAENETUNREACH); #else errno = ENETUNREACH; #endif } else { ret = ::sendmsg(_fd, &meta, portSendFlags); } if (ret == -1) { if (errno != EAGAIN || _timeout == 0) { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription() << ' ' << remoteString() << endl; throw SocketException(SocketException::SEND_ERROR, remoteString()); } else { LOG(_logLevel) << "Socket " << context << " send() remote timeout " << remoteString() << endl; throw SocketException(SocketException::SEND_TIMEOUT, remoteString()); } } else { struct iovec*& i = meta.msg_iov; while (ret > 0) { if (i->iov_len > unsigned(ret)) { i->iov_len -= ret; i->iov_base = (char*)(i->iov_base) + ret; ret = 0; } else { ret -= i->iov_len; ++i; --(meta.msg_iovlen); } } } } #endif } void Socket::recv(char* buf, int len) { while (len > 0) { int ret = -1; if (MONGO_FAIL_POINT(throwSockExcep)) { #if defined(_WIN32) WSASetLastError(WSAENETUNREACH); #else errno = ENETUNREACH; #endif if (ret <= 0) { handleRecvError(ret, len); continue; } } else { ret = unsafe_recv(buf, len); } fassert(16508, ret <= len); len -= ret; buf += ret; } } int Socket::unsafe_recv(char* buf, int max) { int x = _recv(buf, max); _bytesIn += x; return x; } // throws if SSL_read fails or recv returns an error int Socket::_recv(char* buf, int max) { #ifdef MONGO_SSL if (_sslConnection.get()) { return _sslManager->SSL_read(_sslConnection.get(), buf, max); } #endif int ret = ::recv(_fd, buf, max, portRecvFlags); if (ret <= 0) { handleRecvError(ret, max); // If no throw return and call _recv again return 0; } return ret; } void Socket::handleSendError(int ret, const char* context) { #if defined(_WIN32) const int mongo_errno = WSAGetLastError(); if (mongo_errno == WSAETIMEDOUT && _timeout != 0) { #else const int mongo_errno = errno; if ((mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK) && _timeout != 0) { #endif LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl; throw SocketException(SocketException::SEND_TIMEOUT, remoteString()); } else { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl; throw SocketException(SocketException::SEND_ERROR, remoteString()); } } void Socket::handleRecvError(int ret, int len) { if (ret == 0) { LOG(3) << "Socket recv() conn closed? " << remoteString() << endl; throw SocketException(SocketException::CLOSED, remoteString()); } // ret < 0 #if defined(_WIN32) int e = WSAGetLastError(); #else int e = errno; #if defined(EINTR) if (e == EINTR) { LOG(_logLevel) << "EINTR returned from recv(), retrying"; return; } #endif #endif #if defined(_WIN32) // Windows if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { #else if (e == EAGAIN && _timeout > 0) { #endif // this is a timeout LOG(_logLevel) << "Socket recv() timeout " << remoteString() << endl; throw SocketException(SocketException::RECV_TIMEOUT, remoteString()); } LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() << endl; throw SocketException(SocketException::RECV_ERROR, remoteString()); } void Socket::setTimeout(double secs) { setSockTimeouts(_fd, secs); } // TODO: allow modification? // // : secs to wait between stillConnected checks // 0 : always check // -1 : never check const int Socket::errorPollIntervalSecs(5); // Patch to allow better tolerance of flaky network connections that get broken // while we aren't looking. // TODO: Remove when better async changes come. // // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine // if any disconnection-type events have happened on the socket. bool Socket::isStillConnected() { if (MONGO_FAIL_POINT(notStillConnected)) { return false; } if (_fd == -1) { // According to the man page, poll will respond with POLLVNAL for invalid or // unopened descriptors, but it doesn't seem to be properly implemented in // some platforms - it can return 0 events and 0 for revent. Hence this workaround. return false; } if (errorPollIntervalSecs < 0) return true; if (!isPollSupported()) return true; // nothing we can do time_t now = time(0); time_t idleTimeSecs = now - _lastValidityCheckAtSecs; // Only check once every 5 secs if (idleTimeSecs < errorPollIntervalSecs) return true; // Reset our timer, we're checking the connection _lastValidityCheckAtSecs = now; // It's been long enough, poll to see if our socket is still connected pollfd pollInfo; pollInfo.fd = _fd; // We only care about reading the EOF message on clean close (and errors) pollInfo.events = POLLIN; // Poll( info[], size, timeout ) - timeout == 0 => nonblocking int nEvents = socketPoll(&pollInfo, 1, 0); LOG(2) << "polling for status of connection to " << remoteString() << ", " << (nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected") << endl; if (nEvents == 0) { // No events incoming, return still connected AFAWK return true; } else if (nEvents < 0) { // Poll itself failed, this is weird, warn and log errno warning() << "Socket poll() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; // Return true since it's not clear that we're disconnected. return true; } dassert(nEvents == 1); dassert(pollInfo.revents > 0); // Return false at this point, some event happened on the socket, but log what the // actual event was. if (pollInfo.revents & POLLIN) { // There shouldn't really be any data to recv here, so make sure this // is a clean hangup. const int testBufLength = 1024; char testBuf[testBufLength]; int recvd = ::recv(_fd, testBuf, testBufLength, portRecvFlags); if (recvd < 0) { // An error occurred during recv, warn and log errno warning() << "Socket recv() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; } else if (recvd > 0) { // We got nonzero data from this socket, very weird? // Log and warn at runtime, log and abort at devtime // TODO: Dump the data to the log somehow? error() << "Socket found pending " << recvd << " bytes of data during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert(false); } else { // recvd == 0, socket closed remotely, just return false LOG(0) << "Socket closed remotely, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } } else if (pollInfo.revents & POLLHUP) { // A hangup has occurred on this socket LOG(0) << "Socket hangup detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if (pollInfo.revents & POLLERR) { // An error has occurred on this socket LOG(0) << "Socket error detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if (pollInfo.revents & POLLNVAL) { // Socket descriptor itself is weird // Log and warn at runtime, log and abort at devtime error() << "Socket descriptor detected as invalid" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert(false); } else { // Don't know what poll is saying here // Log and warn at runtime, log and abort at devtime error() << "Socket had unknown event (" << static_cast(pollInfo.revents) << ")" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert(false); } return false; } #if defined(_WIN32) MONGO_INITIALIZER(SockWSAStartup)(InitializerContext* context) { WSADATA d; if (WSAStartup(MAKEWORD(2, 2), &d) != 0) { log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl; abort(); } return Status::OK(); } #endif void shutdownNetworking() { #ifdef _WIN32 WSACleanup(); #endif } } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(util_net_sock) mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/sock.h000066400000000000000000000225551273231111400227520ustar00rootroot00000000000000// @file sock.h /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #include #ifndef _WIN32 #include #include #include #include #ifdef __openbsd__ #include #endif #endif // not _WIN32 #include #include #include #include #include "mongo/base/disallow_copying.h" #include "mongo/logger/log_severity.h" #include "mongo/platform/compiler.h" #include "mongo/platform/cstdint.h" #include "mongo/util/assert_util.h" namespace mongo { #ifdef MONGO_SSL class SSLManagerInterface; class SSLConnection; #endif extern const int portSendFlags; extern const int portRecvFlags; const int SOCK_FAMILY_UNKNOWN_ERROR = 13078; void disableNagle(int sock); void shutdownNetworking(); #if defined(_WIN32) typedef short sa_family_t; typedef int socklen_t; // This won't actually be used on windows struct sockaddr_un { short sun_family; char sun_path[108]; // length from unix header }; #else // _WIN32 inline void closesocket(int s) { close(s); } const int INVALID_SOCKET = -1; typedef int SOCKET; #endif // _WIN32 // If an ip address is passed in, just return that. If a hostname is passed // in, look up its ip and return that. Returns "" on failure. std::string hostbyname(const char* hostname); void enableIPv6(bool state = true); bool IPv6Enabled(); void setSockTimeouts(int sock, double secs); /** * wrapped around os representation of network address */ struct MONGO_CLIENT_API SockAddr { SockAddr(); explicit SockAddr(int sourcePort); /* listener side */ SockAddr( const char* ip, int port); /* EndPoint (remote) side, or if you want to specify which interface locally */ template T& as() { return *(T*)(&sa); } template const T& as() const { return *(const T*)(&sa); } std::string toString(bool includePort = true) const; bool isValid() const { return _isValid; } /** * @return one of AF_INET, AF_INET6, or AF_UNIX */ sa_family_t getType() const; unsigned getPort() const; std::string getAddr() const; bool isLocalHost() const; bool operator==(const SockAddr& r) const; bool operator!=(const SockAddr& r) const; bool operator<(const SockAddr& r) const; const sockaddr* raw() const { return (sockaddr*)&sa; } sockaddr* raw() { return (sockaddr*)&sa; } socklen_t addressSize; private: struct sockaddr_storage sa; bool _isValid; }; extern SockAddr unknownAddress; // ( "0.0.0.0", 0 ) /** this is not cache and does a syscall */ std::string getHostName(); /** * thrown by Socket and SockAddr */ class MONGO_CLIENT_API SocketException : public DBException { public: const enum Type { CLOSED, RECV_ERROR, SEND_ERROR, RECV_TIMEOUT, SEND_TIMEOUT, FAILED_STATE, CONNECT_ERROR } _type; SocketException(Type t, const std::string& server, int code = 9001, const std::string& extra = "") : DBException(std::string("socket exception [") + _getStringType(t) + "] for " + server, code), _type(t), _server(server), _extra(extra) {} virtual ~SocketException() throw() {} bool shouldPrint() const { return _type != CLOSED; } virtual std::string toString() const; virtual const std::string* server() const { return &_server; } private: // TODO: Allow exceptions better control over their messages static std::string _getStringType(Type t) { switch (t) { case CLOSED: return "CLOSED"; case RECV_ERROR: return "RECV_ERROR"; case SEND_ERROR: return "SEND_ERROR"; case RECV_TIMEOUT: return "RECV_TIMEOUT"; case SEND_TIMEOUT: return "SEND_TIMEOUT"; case FAILED_STATE: return "FAILED_STATE"; case CONNECT_ERROR: return "CONNECT_ERROR"; default: return "UNKNOWN"; // should never happen } } std::string _server; std::string _extra; }; /** * thin wrapped around file descriptor and system calls * todo: ssl */ class MONGO_CLIENT_API Socket { MONGO_DISALLOW_COPYING(Socket); public: static const int errorPollIntervalSecs; Socket(int sock, const SockAddr& farEnd); /** In some cases the timeout will actually be 2x this value - eg we do a partial send, then the timeout fires, then we try to send again, then the timeout fires again with no data sent, then we detect that the other side is down. Generally you don't want a timeout, you should be very prepared for errors if you set one. */ Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log()); ~Socket(); /** The correct way to initialize and connect to a socket is as follows: (1) construct the * SockAddr, (2) check whether the SockAddr isValid(), (3) if the SockAddr is valid, a * Socket may then try to connect to that SockAddr. It is critical to check the return * value of connect as a false return indicates that there was an error, and the Socket * failed to connect to the given SockAddr. This failure may be due to ConnectBG returning * an error, or due to a timeout on connection, or due to the system socket deciding the * socket is invalid. */ bool connect(SockAddr& farEnd); void close(); void send(const char* data, int len, const char* context); void send(const std::vector >& data, const char* context); // recv len or throw SocketException void recv(char* data, int len); int unsafe_recv(char* buf, int max); logger::LogSeverity getLogLevel() const { return _logLevel; } void setLogLevel(logger::LogSeverity ll) { _logLevel = ll; } SockAddr remoteAddr() const { return _remote; } std::string remoteString() const { return _remote.toString(); } unsigned remotePort() const { return _remote.getPort(); } SockAddr localAddr() const { return _local; } void clearCounters() { _bytesIn = 0; _bytesOut = 0; } long long getBytesIn() const { return _bytesIn; } long long getBytesOut() const { return _bytesOut; } int rawFD() const { return _fd; } void setTimeout(double secs); bool isStillConnected(); void setHandshakeReceived() { _awaitingHandshake = false; } bool isAwaitingHandshake() { return _awaitingHandshake; } #ifdef MONGO_SSL /** secures inline * ssl - Pointer to the global SSLManager. * remoteHost - The hostname of the remote server. */ bool secure(SSLManagerInterface* ssl, const std::string& remoteHost); void secureAccepted(SSLManagerInterface* ssl); #endif /** * This function calls SSL_accept() if SSL-encrypted sockets * are desired. SSL_accept() waits until the remote host calls * SSL_connect(). The return value is the subject name of any * client certificate provided during the handshake. * * @firstBytes is the first bytes received on the socket used * to detect the connection SSL, @len is the number of bytes * * This function may throw SocketException. */ std::string doSSLHandshake(const char* firstBytes = NULL, int len = 0); /** * @return the time when the socket was opened. */ uint64_t getSockCreationMicroSec() const { return _fdCreationMicroSec; } void handleRecvError(int ret, int len); MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context); private: void _init(); /** sends dumbly, just each buffer at a time */ void _send(const std::vector >& data, const char* context); /** raw send, same semantics as ::send with an additional context parameter */ int _send(const char* data, int len, const char* context); /** raw recv, same semantics as ::recv */ int _recv(char* buf, int max); int _fd; uint64_t _fdCreationMicroSec; SockAddr _local; SockAddr _remote; double _timeout; long long _bytesIn; long long _bytesOut; time_t _lastValidityCheckAtSecs; #ifdef MONGO_SSL boost::scoped_ptr _sslConnection; SSLManagerInterface* _sslManager; #endif logger::LogSeverity _logLevel; // passed to log() when logging errors /** true until the first packet has been received or an outgoing connect has been made */ bool _awaitingHandshake; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/sock_test.cpp000066400000000000000000000242541273231111400243420ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/net/sock.h" #include #ifndef _WIN32 #include #include #include #endif #include "mongo/unittest/unittest.h" #include "mongo/util/concurrency/synchronization.h" #include "mongo/util/fail_point_service.h" namespace { using namespace mongo; typedef boost::shared_ptr SocketPtr; typedef std::pair SocketPair; // On UNIX, make a connected pair of PF_LOCAL (aka PF_UNIX) sockets via the native 'socketpair' // call. The 'type' parameter should be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc. // For Win32, we don't have a native socketpair function, so we hack up a connected PF_INET // pair on a random port. SocketPair socketPair(const int type, const int protocol = 0); #if defined(_WIN32) namespace detail { void awaitAccept(SOCKET* acceptSock, SOCKET listenSock, Notification& notify) { *acceptSock = INVALID_SOCKET; const SOCKET result = ::accept(listenSock, NULL, 0); if (result != INVALID_SOCKET) { *acceptSock = result; } notify.notifyOne(); } void awaitConnect(SOCKET* connectSock, const struct addrinfo& where, Notification& notify) { *connectSock = INVALID_SOCKET; SOCKET newSock = ::socket(where.ai_family, where.ai_socktype, where.ai_protocol); if (newSock != INVALID_SOCKET) { int result = ::connect(newSock, where.ai_addr, where.ai_addrlen); if (result == 0) { *connectSock = newSock; } } notify.notifyOne(); } } // namespace detail SocketPair socketPair(const int type, const int protocol) { const int domain = PF_INET; // Create a listen socket and a connect socket. const SOCKET listenSock = ::socket(domain, type, protocol); if (listenSock == INVALID_SOCKET) return SocketPair(); // Bind the listen socket on port zero, it will pick one for us, and start it listening // for connections. struct addrinfo hints, *res; ::memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_socktype = type; hints.ai_flags = AI_PASSIVE; int result = ::getaddrinfo(NULL, "0", &hints, &res); if (result != 0) { closesocket(listenSock); return SocketPair(); } result = ::bind(listenSock, res->ai_addr, res->ai_addrlen); if (result != 0) { closesocket(listenSock); ::freeaddrinfo(res); return SocketPair(); } // Read out the port to which we bound. sockaddr_in bindAddr; ::socklen_t len = sizeof(bindAddr); ::memset(&bindAddr, 0, sizeof(bindAddr)); result = ::getsockname(listenSock, reinterpret_cast(&bindAddr), &len); if (result != 0) { closesocket(listenSock); ::freeaddrinfo(res); return SocketPair(); } result = ::listen(listenSock, 1); if (result != 0) { closesocket(listenSock); ::freeaddrinfo(res); return SocketPair(); } struct addrinfo connectHints, *connectRes; ::memset(&connectHints, 0, sizeof(connectHints)); connectHints.ai_family = PF_INET; connectHints.ai_socktype = type; std::stringstream portStream; portStream << ntohs(bindAddr.sin_port); result = ::getaddrinfo(NULL, portStream.str().c_str(), &connectHints, &connectRes); if (result != 0) { closesocket(listenSock); ::freeaddrinfo(res); return SocketPair(); } // I'd prefer to avoid trying to do this non-blocking on Windows. Just spin up some // threads to do the connect and acccept. Notification accepted; SOCKET acceptSock = INVALID_SOCKET; boost::thread acceptor( stdx::bind(&detail::awaitAccept, &acceptSock, listenSock, boost::ref(accepted))); Notification connected; SOCKET connectSock = INVALID_SOCKET; boost::thread connector( stdx::bind(&detail::awaitConnect, &connectSock, *connectRes, boost::ref(connected))); connected.waitToBeNotified(); connector.join(); if (connectSock == INVALID_SOCKET) { closesocket(listenSock); ::freeaddrinfo(res); ::freeaddrinfo(connectRes); closesocket(acceptSock); closesocket(connectSock); acceptor.join(); return SocketPair(); } accepted.waitToBeNotified(); acceptor.join(); if (acceptSock == INVALID_SOCKET) { closesocket(listenSock); ::freeaddrinfo(res); ::freeaddrinfo(connectRes); closesocket(acceptSock); closesocket(connectSock); return SocketPair(); } closesocket(listenSock); ::freeaddrinfo(res); ::freeaddrinfo(connectRes); SocketPtr first(new Socket(static_cast(acceptSock), SockAddr())); SocketPtr second(new Socket(static_cast(connectSock), SockAddr())); return SocketPair(first, second); } #else // We can just use ::socketpair and wrap up the result in a Socket. SocketPair socketPair(const int type, const int protocol) { // PF_LOCAL is the POSIX name for Unix domain sockets, while PF_UNIX // is the name that BSD used. We use the BSD name because it is more // widely supported (e.g. Solaris 10). const int domain = PF_UNIX; int socks[2]; const int result = ::socketpair(domain, type, protocol, socks); if (result == 0) { return SocketPair(SocketPtr(new Socket(socks[0], SockAddr())), SocketPtr(new Socket(socks[1], SockAddr()))); } return SocketPair(); } #endif // This should match the name of the fail point declared in sock.cpp. const char kSocketFailPointName[] = "throwSockExcep"; class SocketFailPointTest : public unittest::Test { public: SocketFailPointTest() : _failPoint(getGlobalFailPointRegistry()->getFailPoint(kSocketFailPointName)), _sockets(socketPair(SOCK_STREAM)) { // ASSERT_TRUE(_failPoint != NULL); // ASSERT_TRUE(_sockets.first); // ASSERT_TRUE(_sockets.second); } bool trySend() { char byte = 'x'; _sockets.first->send(&byte, sizeof(byte), "SocketFailPointTest::trySend"); return true; } bool trySendVector() { std::vector > data; char byte = 'x'; data.push_back(std::make_pair(&byte, sizeof(byte))); _sockets.first->send(data, "SocketFailPointTest::trySendVector"); return true; } bool tryRecv() { char byte; _sockets.second->recv(&byte, sizeof(byte)); return true; } // You must queue at least one byte on the send socket before calling this function. size_t countRecvable(size_t max) { std::vector buf(max); // This isn't great, because we don't have a guarantee that multiple sends will be // captured in one recv. However, sock doesn't let us pass flags into recv, so we // can't make this non blocking, and therefore can't risk another call. return _sockets.second->unsafe_recv(&buf[0], max); } FailPoint* const _failPoint; const SocketPair _sockets; }; class ScopedFailPointEnabler { public: ScopedFailPointEnabler(FailPoint& fp) : _fp(fp) { _fp.setMode(FailPoint::alwaysOn); } ~ScopedFailPointEnabler() { _fp.setMode(FailPoint::off); } private: FailPoint& _fp; }; TEST_F(SocketFailPointTest, TestSend) { ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); { const ScopedFailPointEnabler enabled(*_failPoint); ASSERT_THROWS(trySend(), SocketException); } // Channel should be working again ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); } TEST_F(SocketFailPointTest, TestSendVector) { ASSERT_TRUE(trySendVector()); ASSERT_TRUE(tryRecv()); { const ScopedFailPointEnabler enabled(*_failPoint); ASSERT_THROWS(trySendVector(), SocketException); } ASSERT_TRUE(trySendVector()); ASSERT_TRUE(tryRecv()); } TEST_F(SocketFailPointTest, TestRecv) { ASSERT_TRUE(trySend()); // data for recv ASSERT_TRUE(tryRecv()); { ASSERT_TRUE(trySend()); // data for recv const ScopedFailPointEnabler enabled(*_failPoint); ASSERT_THROWS(tryRecv(), SocketException); } ASSERT_TRUE(trySend()); // data for recv ASSERT_TRUE(tryRecv()); } TEST_F(SocketFailPointTest, TestFailedSendsDontSend) { ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); { ASSERT_TRUE(trySend()); // queue 1 byte const ScopedFailPointEnabler enabled(*_failPoint); // Fail to queue another byte ASSERT_THROWS(trySend(), SocketException); } // Failed byte should not have been transmitted. ASSERT_EQUALS(size_t(1), countRecvable(2)); } // Ensure that calling send doesn't actually enqueue data to the socket TEST_F(SocketFailPointTest, TestFailedVectorSendsDontSend) { ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); { ASSERT_TRUE(trySend()); // queue 1 byte const ScopedFailPointEnabler enabled(*_failPoint); // Fail to queue another byte ASSERT_THROWS(trySendVector(), SocketException); } // Failed byte should not have been transmitted. ASSERT_EQUALS(size_t(1), countRecvable(2)); } TEST_F(SocketFailPointTest, TestFailedRecvsDontRecv) { ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); { ASSERT_TRUE(trySend()); const ScopedFailPointEnabler enabled(*_failPoint); // Fail to recv that byte ASSERT_THROWS(tryRecv(), SocketException); } // Failed byte should still be queued to recv. ASSERT_EQUALS(size_t(1), countRecvable(1)); // Channel should be working again ASSERT_TRUE(trySend()); ASSERT_TRUE(tryRecv()); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/socket_poll.cpp000066400000000000000000000031571273231111400246610ustar00rootroot00000000000000/** * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/base/init.h" #include "mongo/util/assert_util.h" #include "mongo/util/net/socket_poll.h" namespace mongo { #ifdef _WIN32 typedef int(WSAAPI* WSAPollFunction)(pollfd* fdarray, ULONG nfds, INT timeout); static WSAPollFunction wsaPollFunction = NULL; MONGO_INITIALIZER(DynamicLinkWin32Poll)(InitializerContext* context) { HINSTANCE wsaPollLib = LoadLibraryW(L"Ws2_32.dll"); if (wsaPollLib) { wsaPollFunction = reinterpret_cast(GetProcAddress(wsaPollLib, "WSAPoll")); } return Status::OK(); } bool isPollSupported() { return wsaPollFunction != NULL; } int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout) { fassert(17185, isPollSupported()); return wsaPollFunction(fdarray, nfds, timeout); } #else bool isPollSupported() { return true; } int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout) { return ::poll(fdarray, nfds, timeout); } #endif } MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(util_net_socket_poll) mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/socket_poll.h000066400000000000000000000024551273231111400243260ustar00rootroot00000000000000/** * Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #ifndef _WIN32 #include #else #if defined(NTDDI_VERSION) && (!defined(NTDDI_VISTA) || (NTDDI_VERSION < NTDDI_VISTA)) // These are only defined in winsock2.h on newer windows but we need them everywhere. #define POLLRDNORM 0x0100 #define POLLRDBAND 0x0200 #define POLLIN (POLLRDNORM | POLLRDBAND) #define POLLPRI 0x0400 #define POLLWRNORM 0x0010 #define POLLOUT (POLLWRNORM) #define POLLWRBAND 0x0020 #define POLLERR 0x0001 #define POLLHUP 0x0002 #define POLLNVAL 0x0004 struct pollfd { SOCKET fd; SHORT events; SHORT revents; }; #endif // old windows #endif // ndef _WIN32 namespace mongo { bool isPollSupported(); int socketPoll(pollfd* fdarray, unsigned long nfds, int timeout); } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/ssl_manager.cpp000066400000000000000000001002451273231111400246320ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork #include "mongo/platform/basic.h" #include "mongo/util/net/ssl_manager.h" #include #include #include #include #include #include #include #include "mongo/base/init.h" #include "mongo/platform/atomic_word.h" #include "mongo/client/options.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/sock.h" #include "mongo/util/scopeguard.h" #ifdef MONGO_SSL #include #include #endif using std::endl; namespace mongo { #ifndef MONGO_SSL const std::string getSSLVersion(const std::string& prefix, const std::string& suffix) { return ""; } #else // Old copies of OpenSSL will not have constants to disable protocols they don't support. // Define them to values we can OR together safely to generically disable these protocols across // all versions of OpenSSL. #ifndef SSL_OP_NO_TLSv1_1 #define SSL_OP_NO_TLSv1_1 0 #endif #ifndef SSL_OP_NO_TLSv1_2 #define SSL_OP_NO_TLSv1_2 0 #endif const std::string getSSLVersion(const std::string& prefix, const std::string& suffix) { return prefix + SSLeay_version(SSLEAY_VERSION) + suffix; } namespace { /** * Multithreaded Support for SSL. * * In order to allow OpenSSL to work in a multithreaded environment, you * must provide some callbacks for it to use for locking. The following code * sets up a vector of mutexes and uses thread-local storage to assign an id * to each thread. * The so-called SSLThreadInfo class encapsulates most of the logic required for * OpenSSL multithreaded support. */ unsigned long _ssl_id_callback(); void _ssl_locking_callback(int mode, int type, const char* file, int line); class SSLThreadInfo { public: SSLThreadInfo() { _id = _next.fetchAndAdd(1); } ~SSLThreadInfo() {} unsigned long id() const { return _id; } void lock_callback(int mode, int type, const char* file, int line) { if (mode & CRYPTO_LOCK) { _mutex[type]->lock(); } else { _mutex[type]->unlock(); } } static void init() { while ((int)_mutex.size() < CRYPTO_num_locks()) _mutex.push_back(new boost::recursive_mutex); } static SSLThreadInfo* get() { SSLThreadInfo* me = _thread.get(); if (!me) { me = new SSLThreadInfo(); _thread.reset(me); } return me; } private: unsigned _id; static AtomicUInt32 _next; // Note: see SERVER-8734 for why we are using a recursive mutex here. // Once the deadlock fix in OpenSSL is incorporated into most distros of // Linux, this can be changed back to a nonrecursive mutex. static std::vector _mutex; static boost::thread_specific_ptr _thread; }; unsigned long _ssl_id_callback() { return SSLThreadInfo::get()->id(); } void _ssl_locking_callback(int mode, int type, const char* file, int line) { SSLThreadInfo::get()->lock_callback(mode, type, file, line); } AtomicUInt32 SSLThreadInfo::_next; std::vector SSLThreadInfo::_mutex; boost::thread_specific_ptr SSLThreadInfo::_thread; //////////////////////////////////////////////////////////////// boost::mutex sslManagerMtx; SSLManagerInterface* theSSLManager = NULL; static const int BUFFER_SIZE = 8 * 1024; struct Params { Params(const std::string& pemfile, const std::string& pempwd, const std::string& clusterfile, const std::string& clusterpwd, const std::vector& disabledProtocols, const std::string& cafile = "", const std::string& crlfile = "", const std::string& cipherConfig = "", bool weakCertificateValidation = false, bool allowInvalidCertificates = false, bool allowInvalidHostnames = false, bool fipsMode = false) : pemfile(pemfile), pempwd(pempwd), clusterfile(clusterfile), clusterpwd(clusterpwd), cafile(cafile), crlfile(crlfile), cipherConfig(cipherConfig), disabledProtocols(disabledProtocols), weakCertificateValidation(weakCertificateValidation), allowInvalidCertificates(allowInvalidCertificates), allowInvalidHostnames(allowInvalidHostnames), fipsMode(fipsMode){}; std::string pemfile; std::string pempwd; std::string clusterfile; std::string clusterpwd; std::string cafile; std::string crlfile; std::string cipherConfig; std::vector disabledProtocols; bool weakCertificateValidation; bool allowInvalidCertificates; bool allowInvalidHostnames; bool fipsMode; }; class SSLManager : public SSLManagerInterface { public: explicit SSLManager(const Params& params, bool isServer); virtual ~SSLManager(); virtual SSLConnection* connect(Socket* socket); virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len); virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn, const std::string& remoteHost); virtual void cleanupThreadLocals(); virtual std::string getServerSubjectName() { return _serverSubjectName; } virtual std::string getClientSubjectName() { return _clientSubjectName; } virtual std::string getSSLErrorMessage(int code); virtual int SSL_read(SSLConnection* conn, void* buf, int num); virtual int SSL_write(SSLConnection* conn, const void* buf, int num); virtual unsigned long ERR_get_error(); virtual char* ERR_error_string(unsigned long e, char* buf); virtual int SSL_get_error(const SSLConnection* conn, int ret); virtual int SSL_shutdown(SSLConnection* conn); virtual void SSL_free(SSLConnection* conn); private: SSL_CTX* _serverContext; // SSL context for incoming connections SSL_CTX* _clientContext; // SSL context for outgoing connections std::string _password; bool _validateCertificates; bool _weakValidation; bool _allowInvalidCertificates; bool _allowInvalidHostnames; std::string _serverSubjectName; std::string _clientSubjectName; /** * creates an SSL object to be used for this file descriptor. * caller must SSL_free it. */ SSL* _secure(SSL_CTX* context, int fd); /** * Given an error code from an SSL-type IO function, logs an * appropriate message and throws a SocketException */ MONGO_COMPILER_NORETURN void _handleSSLError(int code, int ret); /* * Init the SSL context using parameters provided in params. */ bool _initSSLContext(SSL_CTX** context, const Params& params); /* * Parse the x509 subject name from the PEM keyfile and store it */ bool _setSubjectName(const std::string& keyFile, std::string& subjectName); /** @return true if was successful, otherwise false */ bool _setupPEM(SSL_CTX* context, const std::string& keyFile, const std::string& password); /* * Set up an SSL context for certificate validation by loading a CA */ bool _setupCA(SSL_CTX* context, const std::string& caFile); /* * Import a certificate revocation list into an SSL context * for use with validating certificates */ bool _setupCRL(SSL_CTX* context, const std::string& crlFile); /* * Activate FIPS 140-2 mode, if the server started with a command line * parameter. */ void _setupFIPS(); /* * sub function for checking the result of an SSL operation */ bool _doneWithSSLOp(SSLConnection* conn, int status); /* * Send and receive network data */ void _flushNetworkBIO(SSLConnection* conn); /* * match a remote host name to an x.509 host name */ bool _hostNameMatch(const char* nameToMatch, const char* certHostName); /** * Callbacks for SSL functions */ static int password_cb(char* buf, int num, int rwflag, void* userdata); static int verify_cb(int ok, X509_STORE_CTX* ctx); }; } // namespace // Global variable indicating if this is a server or a client instance const bool isSSLServer = false; MONGO_INITIALIZER(SSLManager)(InitializerContext* context) { const client::Options& options = client::Options::current(); boost::lock_guard lck(sslManagerMtx); if (options.SSLEnabled()) { const Params params(options.SSLPEMKeyFile(), options.SSLPEMKeyPassword(), std::string(), // server only parameter std::string(), // server only parameter options.SSLDisabledTLSProtocols(), options.SSLCAFile(), options.SSLCRLFile(), options.SSLCipherConfig(), false, // server only parameter options.SSLAllowInvalidCertificates(), options.SSLAllowInvalidHostnames(), options.FIPSMode()); theSSLManager = new SSLManager(params, isSSLServer); } return Status::OK(); } SSLManagerInterface* getSSLManager() { boost::lock_guard lck(sslManagerMtx); if (theSSLManager) return theSSLManager; return NULL; } std::string getCertificateSubjectName(X509* cert) { std::string result; BIO* out = BIO_new(BIO_s_mem()); uassert(16884, "unable to allocate BIO memory", NULL != out); ON_BLOCK_EXIT(BIO_free, out); if (X509_NAME_print_ex(out, X509_get_subject_name(cert), 0, XN_FLAG_RFC2253) >= 0) { if (BIO_number_written(out) > 0) { result.resize(BIO_number_written(out)); BIO_read(out, &result[0], result.size()); } } else { log() << "failed to convert subject name to RFC2253 format" << endl; } return result; } SSLConnection::SSLConnection(SSL_CTX* context, Socket* sock, const char* initialBytes, int len) : socket(sock) { // This just ensures that SSL multithreading support is set up for this thread, // if it's not already. SSLThreadInfo::get(); ssl = SSL_new(context); std::string sslErr = NULL != getSSLManager() ? getSSLManager()->getSSLErrorMessage(ERR_get_error()) : ""; massert(15861, "Error creating new SSL object " + sslErr, ssl); BIO_new_bio_pair(&internalBIO, BUFFER_SIZE, &networkBIO, BUFFER_SIZE); SSL_set_bio(ssl, internalBIO, internalBIO); if (len > 0) { int toBIO = BIO_write(networkBIO, initialBytes, len); if (toBIO != len) { LOG(3) << "Failed to write initial network data to the SSL BIO layer"; throw SocketException(SocketException::RECV_ERROR, socket->remoteString()); } } } SSLConnection::~SSLConnection() { if (ssl) { // The internalBIO is automatically freed as part of SSL_free SSL_free(ssl); } if (networkBIO) { BIO_free(networkBIO); } } SSLManagerInterface::~SSLManagerInterface() {} SSLManager::SSLManager(const Params& params, bool isServer) : _validateCertificates(false), _weakValidation(params.weakCertificateValidation), _allowInvalidCertificates(params.allowInvalidCertificates), _allowInvalidHostnames(params.allowInvalidHostnames) { SSL_library_init(); SSL_load_error_strings(); ERR_load_crypto_strings(); if (params.fipsMode) { _setupFIPS(); } // Add all digests and ciphers to OpenSSL's internal table // so that encryption/decryption is backwards compatible OpenSSL_add_all_algorithms(); // Setup OpenSSL multithreading callbacks CRYPTO_set_id_callback(_ssl_id_callback); CRYPTO_set_locking_callback(_ssl_locking_callback); SSLThreadInfo::init(); SSLThreadInfo::get(); if (!_initSSLContext(&_clientContext, params)) { uasserted(16768, "ssl initialization problem"); } // SSL client specific initialization if (!isServer) { _serverContext = NULL; if (!params.pemfile.empty()) { if (!_setSubjectName(params.pemfile, _clientSubjectName)) { uasserted(16941, "ssl initialization problem"); } } } // SSL server specific initialization if (isServer) { if (!_initSSLContext(&_serverContext, params)) { uasserted(16562, "ssl initialization problem"); } if (!_setSubjectName(params.pemfile, _serverSubjectName)) { uasserted(16942, "ssl initialization problem"); } // use the cluster certificate for outgoing connections if specified if (!params.clusterfile.empty()) { if (!_setSubjectName(params.clusterfile, _clientSubjectName)) { uasserted(16943, "ssl initialization problem"); } } else { if (!_setSubjectName(params.pemfile, _clientSubjectName)) { uasserted(16944, "ssl initialization problem"); } } } } SSLManager::~SSLManager() { CRYPTO_set_id_callback(0); ERR_free_strings(); EVP_cleanup(); if (NULL != _serverContext) { SSL_CTX_free(_serverContext); } if (NULL != _clientContext) { SSL_CTX_free(_clientContext); } } int SSLManager::password_cb(char* buf, int num, int rwflag, void* userdata) { // Unless OpenSSL misbehaves, num should always be positive fassert(17314, num > 0); SSLManager* sm = static_cast(userdata); const size_t copied = sm->_password.copy(buf, num - 1); buf[copied] = '\0'; return copied; } int SSLManager::verify_cb(int ok, X509_STORE_CTX* ctx) { return 1; // always succeed; we will catch the error in our get_verify_result() call } int SSLManager::SSL_read(SSLConnection* conn, void* buf, int num) { int status; do { status = ::SSL_read(conn->ssl, buf, num); } while (!_doneWithSSLOp(conn, status)); if (status <= 0) _handleSSLError(SSL_get_error(conn, status), status); return status; } int SSLManager::SSL_write(SSLConnection* conn, const void* buf, int num) { int status; do { status = ::SSL_write(conn->ssl, buf, num); } while (!_doneWithSSLOp(conn, status)); if (status <= 0) _handleSSLError(SSL_get_error(conn, status), status); return status; } unsigned long SSLManager::ERR_get_error() { return ::ERR_get_error(); } char* SSLManager::ERR_error_string(unsigned long e, char* buf) { return ::ERR_error_string(e, buf); } int SSLManager::SSL_get_error(const SSLConnection* conn, int ret) { return ::SSL_get_error(conn->ssl, ret); } int SSLManager::SSL_shutdown(SSLConnection* conn) { int status; do { status = ::SSL_shutdown(conn->ssl); } while (!_doneWithSSLOp(conn, status)); if (status < 0) _handleSSLError(SSL_get_error(conn, status), status); return status; } void SSLManager::SSL_free(SSLConnection* conn) { return ::SSL_free(conn->ssl); } void SSLManager::_setupFIPS() { // Turn on FIPS mode if requested. // OPENSSL_FIPS must be defined by the OpenSSL headers, plus MONGO_SSL_FIPS // must be defined via a MongoDB build flag. #if defined(MONGO_HAVE_FIPS_MODE_SET) int status = FIPS_mode_set(1); if (!status) { severe() << "can't activate FIPS mode: " << getSSLErrorMessage(ERR_get_error()) << endl; fassertFailed(16703); } log() << "FIPS 140-2 mode activated" << endl; #else severe() << "this version of mongodb was not compiled with FIPS support"; fassertFailed(17089); #endif } bool SSLManager::_initSSLContext(SSL_CTX** context, const Params& params) { *context = SSL_CTX_new(SSLv23_method()); massert(15864, mongoutils::str::stream() << "can't create SSL Context: " << getSSLErrorMessage(ERR_get_error()), context); // SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's. // SSL_OP_NO_SSLv2 - Disable SSL v2 support // SSL_OP_NO_SSLv3 - Disable SSL v3 support long supportedProtocols = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; // Set the supported TLS protocols. Allow --disabledProtocols to disable selected ciphers. if (!params.disabledProtocols.empty()) { for (std::vector::const_iterator it = params.disabledProtocols.begin(); it != params.disabledProtocols.end(); ++it) { if (*it == client::Options::kTLS1_0) { supportedProtocols |= SSL_OP_NO_TLSv1; } else if (*it == client::Options::kTLS1_1) { supportedProtocols |= SSL_OP_NO_TLSv1_1; } else if (*it == client::Options::kTLS1_2) { supportedProtocols |= SSL_OP_NO_TLSv1_2; } } } SSL_CTX_set_options(*context, supportedProtocols); // HIGH - Enable strong ciphers // !EXPORT - Disable export ciphers (40/56 bit) // !aNULL - Disable anonymous auth ciphers // @STRENGTH - Sort ciphers based on strength std::string cipherConfig = "HIGH:!EXPORT:!aNULL@STRENGTH"; // Allow the cipher configuration string to be overriden by --sslCipherConfig if (!params.cipherConfig.empty()) { cipherConfig = params.cipherConfig; } massert(28615, mongoutils::str::stream() << "can't set supported cipher suites: " << getSSLErrorMessage(ERR_get_error()), SSL_CTX_set_cipher_list(*context, cipherConfig.c_str())); // If renegotiation is needed, don't return from recv() or send() until it's successful. // Note: this is for blocking sockets only. SSL_CTX_set_mode(*context, SSL_MODE_AUTO_RETRY); massert(28607, mongoutils::str::stream() << "can't store ssl session id context: " << getSSLErrorMessage(ERR_get_error()), SSL_CTX_set_session_id_context(*context, static_cast(static_cast(context)), sizeof(*context))); // Use the clusterfile for internal outgoing SSL connections if specified if (context == &_clientContext && !params.clusterfile.empty()) { EVP_set_pw_prompt("Enter cluster certificate passphrase"); if (!_setupPEM(*context, params.clusterfile, params.clusterpwd)) { return false; } } // Use the pemfile for everything else else if (!params.pemfile.empty()) { EVP_set_pw_prompt("Enter PEM passphrase"); if (!_setupPEM(*context, params.pemfile, params.pempwd)) { return false; } } if (!params.cafile.empty()) { // Set up certificate validation with a certificate authority if (!_setupCA(*context, params.cafile)) { return false; } } if (!params.crlfile.empty()) { if (!_setupCRL(*context, params.crlfile)) { return false; } } return true; } bool SSLManager::_setSubjectName(const std::string& keyFile, std::string& subjectName) { // Read the certificate subject name and store it BIO* in = BIO_new(BIO_s_file_internal()); if (NULL == in) { error() << "failed to allocate BIO object: " << getSSLErrorMessage(ERR_get_error()) << endl; return false; } ON_BLOCK_EXIT(BIO_free, in); if (BIO_read_filename(in, keyFile.c_str()) <= 0) { error() << "cannot read key file when setting subject name: " << keyFile << ' ' << getSSLErrorMessage(ERR_get_error()) << endl; return false; } X509* x509 = PEM_read_bio_X509(in, NULL, &SSLManager::password_cb, this); if (NULL == x509) { error() << "cannot retrieve certificate from keyfile: " << keyFile << ' ' << getSSLErrorMessage(ERR_get_error()) << endl; return false; } ON_BLOCK_EXIT(X509_free, x509); subjectName = getCertificateSubjectName(x509); return true; } bool SSLManager::_setupPEM(SSL_CTX* context, const std::string& keyFile, const std::string& password) { _password = password; if (SSL_CTX_use_certificate_chain_file(context, keyFile.c_str()) != 1) { error() << "cannot read certificate file: " << keyFile << ' ' << getSSLErrorMessage(ERR_get_error()) << endl; return false; } // If password is empty, use default OpenSSL callback, which uses the terminal // to securely request the password interactively from the user. if (!password.empty()) { SSL_CTX_set_default_passwd_cb_userdata(context, this); SSL_CTX_set_default_passwd_cb(context, &SSLManager::password_cb); } if (SSL_CTX_use_PrivateKey_file(context, keyFile.c_str(), SSL_FILETYPE_PEM) != 1) { error() << "cannot read PEM key file: " << keyFile << ' ' << getSSLErrorMessage(ERR_get_error()) << endl; return false; } // Verify that the certificate and the key go together. if (SSL_CTX_check_private_key(context) != 1) { error() << "SSL certificate validation: " << getSSLErrorMessage(ERR_get_error()) << endl; return false; } return true; } bool SSLManager::_setupCA(SSL_CTX* context, const std::string& caFile) { // Set the list of CAs sent to clients STACK_OF(X509_NAME)* certNames = SSL_load_client_CA_file(caFile.c_str()); if (certNames == NULL) { error() << "cannot read certificate authority file: " << caFile << " " << getSSLErrorMessage(ERR_get_error()) << endl; return false; } SSL_CTX_set_client_CA_list(context, certNames); // Load trusted CA if (SSL_CTX_load_verify_locations(context, caFile.c_str(), NULL) != 1) { error() << "cannot read certificate authority file: " << caFile << " " << getSSLErrorMessage(ERR_get_error()) << endl; return false; } // Set SSL to require peer (client) certificate verification // if a certificate is presented SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManager::verify_cb); _validateCertificates = true; return true; } bool SSLManager::_setupCRL(SSL_CTX* context, const std::string& crlFile) { X509_STORE* store = SSL_CTX_get_cert_store(context); fassert(16583, store); X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); X509_LOOKUP* lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); fassert(16584, lookup); int status = X509_load_crl_file(lookup, crlFile.c_str(), X509_FILETYPE_PEM); if (status == 0) { error() << "cannot read CRL file: " << crlFile << ' ' << getSSLErrorMessage(ERR_get_error()) << endl; return false; } log() << "ssl imported " << status << " revoked certificate" << ((status == 1) ? "" : "s") << " from the revocation list." << endl; return true; } /* * The interface layer between network and BIO-pair. The BIO-pair buffers * the data to/from the TLS layer. */ void SSLManager::_flushNetworkBIO(SSLConnection* conn) { char buffer[BUFFER_SIZE]; int wantWrite; /* * Write the complete contents of the buffer. Leaving the buffer * unflushed could cause a deadlock. */ while ((wantWrite = BIO_ctrl_pending(conn->networkBIO)) > 0) { if (wantWrite > BUFFER_SIZE) { wantWrite = BUFFER_SIZE; } int fromBIO = BIO_read(conn->networkBIO, buffer, wantWrite); int writePos = 0; do { int numWrite = fromBIO - writePos; numWrite = send(conn->socket->rawFD(), buffer + writePos, numWrite, portSendFlags); if (numWrite < 0) { conn->socket->handleSendError(numWrite, ""); } writePos += numWrite; } while (writePos < fromBIO); } int wantRead; while ((wantRead = BIO_ctrl_get_read_request(conn->networkBIO)) > 0) { if (wantRead > BUFFER_SIZE) { wantRead = BUFFER_SIZE; } int numRead = recv(conn->socket->rawFD(), buffer, wantRead, portRecvFlags); if (numRead <= 0) { conn->socket->handleRecvError(numRead, wantRead); continue; } int toBIO = BIO_write(conn->networkBIO, buffer, numRead); if (toBIO != numRead) { LOG(3) << "Failed to write network data to the SSL BIO layer"; throw SocketException(SocketException::RECV_ERROR, conn->socket->remoteString()); } } } bool SSLManager::_doneWithSSLOp(SSLConnection* conn, int status) { int sslErr = SSL_get_error(conn, status); switch (sslErr) { case SSL_ERROR_NONE: _flushNetworkBIO(conn); // success, flush network BIO before leaving return true; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: _flushNetworkBIO(conn); // not ready, flush network BIO and try again return false; default: return true; } } SSLConnection* SSLManager::connect(Socket* socket) { std::auto_ptr sslConn(new SSLConnection(_clientContext, socket, NULL, 0)); int ret; do { ret = ::SSL_connect(sslConn->ssl); } while (!_doneWithSSLOp(sslConn.get(), ret)); if (ret != 1) _handleSSLError(SSL_get_error(sslConn.get(), ret), ret); return sslConn.release(); } SSLConnection* SSLManager::accept(Socket* socket, const char* initialBytes, int len) { std::auto_ptr sslConn( new SSLConnection(_serverContext, socket, initialBytes, len)); int ret; do { ret = ::SSL_accept(sslConn->ssl); } while (!_doneWithSSLOp(sslConn.get(), ret)); if (ret != 1) _handleSSLError(SSL_get_error(sslConn.get(), ret), ret); return sslConn.release(); } // TODO SERVER-11601 Use NFC Unicode canonicalization bool SSLManager::_hostNameMatch(const char* nameToMatch, const char* certHostName) { if (strlen(certHostName) < 2) { return false; } // match wildcard DNS names if (certHostName[0] == '*' && certHostName[1] == '.') { // allow name.example.com if the cert is *.example.com, '*' does not match '.' const char* subName = strchr(nameToMatch, '.'); return subName && !strcasecmp(certHostName + 1, subName); } else { return !strcasecmp(nameToMatch, certHostName); } } std::string SSLManager::parseAndValidatePeerCertificate(const SSLConnection* conn, const std::string& remoteHost) { // only set if a CA cert has been provided if (!_validateCertificates) return ""; X509* peerCert = SSL_get_peer_certificate(conn->ssl); if (NULL == peerCert) { // no certificate presented by peer if (_weakValidation) { warning() << "no SSL certificate provided by peer" << endl; } else { error() << "no SSL certificate provided by peer; connection rejected" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); } return ""; } ON_BLOCK_EXIT(X509_free, peerCert); long result = SSL_get_verify_result(conn->ssl); if (result != X509_V_OK) { if (_allowInvalidCertificates) { warning() << "SSL peer certificate validation failed:" << X509_verify_cert_error_string(result); } else { error() << "SSL peer certificate validation failed:" << X509_verify_cert_error_string(result); throw SocketException(SocketException::CONNECT_ERROR, ""); } } // TODO: check optional cipher restriction, using cert. std::string peerSubjectName = getCertificateSubjectName(peerCert); // If this is an SSL client context (on a MongoDB server or client) // perform hostname validation of the remote server if (remoteHost.empty()) { return peerSubjectName; } // Try to match using the Subject Alternate Name, if it exists. // RFC-2818 requires the Subject Alternate Name to be used if present. // Otherwise, the most specific Common Name field in the subject field // must be used. bool sanMatch = false; bool cnMatch = false; STACK_OF(GENERAL_NAME)* sanNames = static_cast( X509_get_ext_d2i(peerCert, NID_subject_alt_name, NULL, NULL)); if (sanNames != NULL) { int sanNamesList = sk_GENERAL_NAME_num(sanNames); for (int i = 0; i < sanNamesList; i++) { const GENERAL_NAME* currentName = sk_GENERAL_NAME_value(sanNames, i); if (currentName && currentName->type == GEN_DNS) { char* dnsName = reinterpret_cast(ASN1_STRING_data(currentName->d.dNSName)); if (_hostNameMatch(remoteHost.c_str(), dnsName)) { sanMatch = true; break; } } } sk_GENERAL_NAME_pop_free(sanNames, GENERAL_NAME_free); } else { // If Subject Alternate Name (SAN) didn't exist, check Common Name (CN). int cnBegin = peerSubjectName.find("CN=") + 3; int cnEnd = peerSubjectName.find(",", cnBegin); std::string commonName = peerSubjectName.substr(cnBegin, cnEnd - cnBegin); if (_hostNameMatch(remoteHost.c_str(), commonName.c_str())) { cnMatch = true; } } if (!sanMatch && !cnMatch) { if (_allowInvalidCertificates || _allowInvalidHostnames) { warning() << "The server certificate does not match the host name " << remoteHost; } else { error() << "The server certificate does not match the host name " << remoteHost; throw SocketException(SocketException::CONNECT_ERROR, ""); } } return peerSubjectName; } void SSLManager::cleanupThreadLocals() { ERR_remove_state(0); } std::string SSLManager::getSSLErrorMessage(int code) { // 120 from the SSL documentation for ERR_error_string static const size_t msglen = 120; char msg[msglen]; ERR_error_string_n(code, msg, msglen); return msg; } void SSLManager::_handleSSLError(int code, int ret) { int err = ERR_get_error(); switch (code) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: // should not happen because we turned on AUTO_RETRY // However, it turns out this CAN happen during a connect, if the other side // accepts the socket connection but fails to do the SSL handshake in a timely // manner. error() << "SSL: " << code << ", possibly timed out during connect"; break; case SSL_ERROR_ZERO_RETURN: // TODO: Check if we can avoid throwing an exception for this condition LOG(3) << "SSL network connection closed"; break; case SSL_ERROR_SYSCALL: // If ERR_get_error returned 0, the error queue is empty // check the return value of the actual SSL operation if (err != 0) { error() << "SSL: " << getSSLErrorMessage(err); } else if (ret == 0) { error() << "Unexpected EOF encountered during SSL communication"; } else { error() << "The SSL BIO reported an I/O error " << errnoWithDescription(); } break; case SSL_ERROR_SSL: { error() << "SSL: " << getSSLErrorMessage(err); break; } default: error() << "unrecognized SSL error"; break; } throw SocketException(SocketException::CONNECT_ERROR, ""); } #endif // #ifdef MONGO_SSL } MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(util_net_ssl_manager) mongo-cxx-driver-legacy-1.1.2/src/mongo/util/net/ssl_manager.h000066400000000000000000000067451273231111400243110ustar00rootroot00000000000000/* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/config.h" #include #ifdef MONGO_SSL #include "mongo/base/disallow_copying.h" #include "mongo/util/net/sock.h" #include #include #endif // #ifdef MONGO_SSL namespace mongo { /* * @return the SSL version string prefixed with prefix and suffixed with suffix */ const std::string getSSLVersion(const std::string& prefix, const std::string& suffix); } #ifdef MONGO_SSL namespace mongo { class SSLConnection { public: SSL* ssl; BIO* networkBIO; BIO* internalBIO; Socket* socket; SSLConnection(SSL_CTX* ctx, Socket* sock, const char* initialBytes, int len); ~SSLConnection(); }; class SSLManagerInterface { public: virtual ~SSLManagerInterface(); /** * Initiates a TLS connection. * Throws SocketException on failure. * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor */ virtual SSLConnection* connect(Socket* socket) = 0; /** * Waits for the other side to initiate a TLS connection. * Throws SocketException on failure. * @return a pointer to an SSLConnection. Resources are freed in SSLConnection's destructor */ virtual SSLConnection* accept(Socket* socket, const char* initialBytes, int len) = 0; /** * Fetches a peer certificate and validates it if it exists * Throws SocketException on failure * @return a std::string containing the certificate's subject name. */ virtual std::string parseAndValidatePeerCertificate(const SSLConnection* conn, const std::string& remoteHost) = 0; /** * Cleans up SSL thread local memory; use at thread exit * to avoid memory leaks */ virtual void cleanupThreadLocals() = 0; /** * Gets the subject name of our own server certificate * @return the subject name. */ virtual std::string getServerSubjectName() = 0; /** * Gets the subject name of our own client certificate * used for cluster authentiation * @return the subject name. */ virtual std::string getClientSubjectName() = 0; /** * Fetches the error text for an error code, in a thread-safe manner. */ virtual std::string getSSLErrorMessage(int code) = 0; /** * ssl.h wrappers */ virtual int SSL_read(SSLConnection* conn, void* buf, int num) = 0; virtual int SSL_write(SSLConnection* conn, const void* buf, int num) = 0; virtual unsigned long ERR_get_error() = 0; virtual char* ERR_error_string(unsigned long e, char* buf) = 0; virtual int SSL_get_error(const SSLConnection* conn, int ret) = 0; virtual int SSL_shutdown(SSLConnection* conn) = 0; virtual void SSL_free(SSLConnection* conn) = 0; }; // Access SSL functions through this instance. SSLManagerInterface* getSSLManager(); } #endif // #ifdef MONGO_SSL mongo-cxx-driver-legacy-1.1.2/src/mongo/util/password_digest.cpp000066400000000000000000000022741273231111400247550ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/password_digest.h" namespace mongo { std::string createPasswordDigest(const StringData& username, const StringData& clearTextPassword) { md5digest d; { md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t*)username.rawData(), username.size()); md5_append(&st, (const md5_byte_t*)":mongo:", 7); md5_append(&st, (const md5_byte_t*)clearTextPassword.rawData(), clearTextPassword.size()); md5_finish(&st, d); } return digestToString(d); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/password_digest.h000066400000000000000000000017201273231111400244150ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/string_data.h" #include "mongo/util/md5.hpp" namespace mongo { /** * Hashes the password so that it can be stored in a user object or used for MONGODB-CR * authentication. */ std::string createPasswordDigest(const StringData& username, const StringData& clearTextPassword); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/scopeguard.h000066400000000000000000000255401273231111400233560ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2000 Andrei Alexandrescu // Copyright (c) 2000 Petru Marginean // Copyright (c) 2005 Joshua Lehrer // // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author makes no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_SCOPEGUARD_H_ #define LOKI_SCOPEGUARD_H_ #include "mongo/platform/compiler.h" namespace mongo { //////////////////////////////////////////////////////////////////////////////// /// \class RefToValue /// /// Transports a reference as a value /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard //////////////////////////////////////////////////////////////////////////////// template class RefToValue { public: RefToValue(T& ref) : ref_(ref) {} RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) {} operator T&() const { return ref_; } private: // Disable - not implemented RefToValue(); RefToValue& operator=(const RefToValue&); T& ref_; }; //////////////////////////////////////////////////////////////////////////////// /// RefToValue creator. //////////////////////////////////////////////////////////////////////////////// template inline RefToValue ByRef(T& t) { return RefToValue(t); } //////////////////////////////////////////// /// ScopeGuard /* Trivial example for use: FILE* f = fopen("myfile.txt", "w+"); if (!f) return error; ON_BLOCK_EXIT(fclose, f); More complicated example: ScopeGuard guard = MakeGuard(my_rollback_func, myparam); ... if (successful) { guard.Dismiss(); return; } // guard is still active here and will fire at scope exit ... */ class ScopeGuardImplBase { ScopeGuardImplBase& operator=(const ScopeGuardImplBase&); protected: ~ScopeGuardImplBase() {} ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() : dismissed_(other.dismissed_) { other.Dismiss(); } template static void SafeExecute(J& j) throw() { if (!j.dismissed_) try { j.Execute(); } catch (...) { } } mutable bool dismissed_; public: ScopeGuardImplBase() throw() : dismissed_(false) {} void Dismiss() const throw() { dismissed_ = true; } }; //////////////////////////////////////////////////////////////// /// /// \typedef typedef const ScopeGuardImplBase& ScopeGuard /// /// See Andrei's and Petru Marginean's CUJ article /// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm /// /// Changes to the original code by Joshua Lehrer: /// http://www.lehrerfamily.com/scopeguard.html //////////////////////////////////////////////////////////////// typedef const ScopeGuardImplBase& ScopeGuard; template class ScopeGuardImpl0 : public ScopeGuardImplBase { public: static ScopeGuardImpl0 MakeGuard(F fun) { return ScopeGuardImpl0(fun); } ~ScopeGuardImpl0() throw() { SafeExecute(*this); } void Execute() { fun_(); } protected: ScopeGuardImpl0(F fun) : fun_(fun) {} F fun_; }; template inline ScopeGuardImpl0 MakeGuard(F fun) { return ScopeGuardImpl0::MakeGuard(fun); } template class ScopeGuardImpl1 : public ScopeGuardImplBase { public: static ScopeGuardImpl1 MakeGuard(F fun, P1 p1) { return ScopeGuardImpl1(fun, p1); } ~ScopeGuardImpl1() throw() { SafeExecute(*this); } void Execute() { fun_(p1_); } protected: ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) {} F fun_; const P1 p1_; }; template inline ScopeGuardImpl1 MakeGuard(F fun, P1 p1) { return ScopeGuardImpl1::MakeGuard(fun, p1); } template class ScopeGuardImpl2 : public ScopeGuardImplBase { public: static ScopeGuardImpl2 MakeGuard(F fun, P1 p1, P2 p2) { return ScopeGuardImpl2(fun, p1, p2); } ~ScopeGuardImpl2() throw() { SafeExecute(*this); } void Execute() { fun_(p1_, p2_); } protected: ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) {} F fun_; const P1 p1_; const P2 p2_; }; template inline ScopeGuardImpl2 MakeGuard(F fun, P1 p1, P2 p2) { return ScopeGuardImpl2::MakeGuard(fun, p1, p2); } template class ScopeGuardImpl3 : public ScopeGuardImplBase { public: static ScopeGuardImpl3 MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { return ScopeGuardImpl3(fun, p1, p2, p3); } ~ScopeGuardImpl3() throw() { SafeExecute(*this); } void Execute() { fun_(p1_, p2_, p3_); } protected: ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3) {} F fun_; const P1 p1_; const P2 p2_; const P3 p3_; }; template inline ScopeGuardImpl3 MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { return ScopeGuardImpl3::MakeGuard(fun, p1, p2, p3); } //************************************************************ template class ObjScopeGuardImpl0 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl0 MakeObjGuard(Obj& obj, MemFun memFun) { return ObjScopeGuardImpl0(obj, memFun); } ~ObjScopeGuardImpl0() throw() { SafeExecute(*this); } void Execute() { (obj_.*memFun_)(); } protected: ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) {} Obj& obj_; MemFun memFun_; }; template inline ObjScopeGuardImpl0 MakeObjGuard(Obj& obj, MemFun memFun) { return ObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } template inline ObjScopeGuardImpl0 MakeGuard(Ret (Obj2::*memFun)(), Obj1& obj) { return ObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } template inline ObjScopeGuardImpl0 MakeGuard(Ret (Obj2::*memFun)(), Obj1* obj) { return ObjScopeGuardImpl0::MakeObjGuard(*obj, memFun); } template class ObjScopeGuardImpl1 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl1 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { return ObjScopeGuardImpl1(obj, memFun, p1); } ~ObjScopeGuardImpl1() throw() { SafeExecute(*this); } void Execute() { (obj_.*memFun_)(p1_); } protected: ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1) {} Obj& obj_; MemFun memFun_; const P1 p1_; }; template inline ObjScopeGuardImpl1 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { return ObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } template inline ObjScopeGuardImpl1 MakeGuard(Ret (Obj2::*memFun)(P1a), Obj1& obj, P1b p1) { return ObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } template inline ObjScopeGuardImpl1 MakeGuard(Ret (Obj2::*memFun)(P1a), Obj1* obj, P1b p1) { return ObjScopeGuardImpl1::MakeObjGuard(*obj, memFun, p1); } template class ObjScopeGuardImpl2 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl2 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { return ObjScopeGuardImpl2(obj, memFun, p1, p2); } ~ObjScopeGuardImpl2() throw() { SafeExecute(*this); } void Execute() { (obj_.*memFun_)(p1_, p2_); } protected: ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {} Obj& obj_; MemFun memFun_; const P1 p1_; const P2 p2_; }; template inline ObjScopeGuardImpl2 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { return ObjScopeGuardImpl2::MakeObjGuard(obj, memFun, p1, p2); } template inline ObjScopeGuardImpl2 MakeGuard( Ret (Obj2::*memFun)(P1a, P2a), Obj1& obj, P1b p1, P2b p2) { return ObjScopeGuardImpl2::MakeObjGuard( obj, memFun, p1, p2); } template inline ObjScopeGuardImpl2 MakeGuard( Ret (Obj2::*memFun)(P1a, P2a), Obj1* obj, P1b p1, P2b p2) { return ObjScopeGuardImpl2::MakeObjGuard( *obj, memFun, p1, p2); } } // namespace Loki #define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2 #define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2) #define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__) #define ON_BLOCK_EXIT \ MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard #define ON_BLOCK_EXIT_OBJ \ MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard #endif // LOKI_SCOPEGUARD_H_ mongo-cxx-driver-legacy-1.1.2/src/mongo/util/shared_buffer.h000066400000000000000000000063171273231111400240220ustar00rootroot00000000000000/** * Copyright (C) 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/platform/atomic_word.h" namespace mongo { class SharedBuffer { public: SharedBuffer() {} void swap(SharedBuffer& other) { _holder.swap(other._holder); } /** * C++03 compatible way of writing std::move(someSharedBuffer) */ SharedBuffer moveFrom() { SharedBuffer out; this->swap(out); return out; } static SharedBuffer allocate(size_t bytes) { return takeOwnership(static_cast(malloc(sizeof(Holder) + bytes))); } /** * Given a pointer to a region of un-owned data, prefixed by sufficient space for a * SharedBuffer::Holder object, return an SharedBuffer that owns the * memory. * * This class will call free(holderPrefixedData), so it must have been allocated in a way * that makes that valid. */ static SharedBuffer takeOwnership(char* holderPrefixedData) { // Initialize the refcount to 1 so we don't need to increment it in the constructor // (see private Holder* constructor below). // // TODO: Should dassert alignment of holderPrefixedData // here if possible. return SharedBuffer(new (holderPrefixedData) Holder(1U)); } char* get() const { return _holder ? _holder->data() : NULL; } class Holder { public: explicit Holder(AtomicUInt32::WordType initial = AtomicUInt32::WordType()) : _refCount(initial) {} // these are called automatically by boost::intrusive_ptr friend void intrusive_ptr_add_ref(Holder* h) { h->_refCount.fetchAndAdd(1); } friend void intrusive_ptr_release(Holder* h) { if (h->_refCount.subtractAndFetch(1) == 0) { // We placement new'ed a Holder in takeOwnership above, // so we must destroy the object here. h->~Holder(); free(h); } } char* data() { return reinterpret_cast(this + 1); } const char* data() const { return reinterpret_cast(this + 1); } private: AtomicUInt32 _refCount; }; private: explicit SharedBuffer(Holder* holder) : _holder(holder, /*add_ref=*/false) { // NOTE: The 'false' above is because we have already initialized the Holder with a // refcount of '1' in takeOwnership above. This avoids an atomic increment. } boost::intrusive_ptr _holder; }; inline void swap(SharedBuffer& one, SharedBuffer& two) { one.swap(two); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/string_map.h000066400000000000000000000032761273231111400233670ustar00rootroot00000000000000// string_map.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/base/string_data.h" #include "mongo/util/unordered_fast_key_table.h" namespace mongo { typedef StringData::Hasher StringMapDefaultHash; struct StringMapDefaultEqual { bool operator()(const StringData& a, const StringData& b) const { return a == b; } }; struct StringMapDefaultConvertor { StringData operator()(const std::string& s) const { return StringData(s); } }; struct StringMapDefaultConvertorOther { std::string operator()(const StringData& s) const { return s.toString(); } }; template class StringMap : public UnorderedFastKeyTable {}; } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/string_map_test.cpp000066400000000000000000000111741273231111400247550ustar00rootroot00000000000000// string_map_test.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include "mongo/unittest/unittest.h" #include "mongo/platform/random.h" #include "mongo/platform/unordered_map.h" #include "mongo/util/string_map.h" #include "mongo/util/log.h" #include "mongo/util/timer.h" namespace { using namespace mongo; TEST(StringMapTest, Hash1) { StringMapDefaultHash h; ASSERT_EQUALS(h(""), h("")); ASSERT_EQUALS(h("a"), h("a")); ASSERT_EQUALS(h("abc"), h("abc")); ASSERT_NOT_EQUALS(h(""), h("a")); ASSERT_NOT_EQUALS(h("a"), h("ab")); ASSERT_NOT_EQUALS(h("foo28"), h("foo35")); } #define equalsBothWays(a, b) \ ASSERT_TRUE(e((a), (b))); \ ASSERT_TRUE(e((b), (a))); #define notEqualsBothWays(a, b) \ ASSERT_FALSE(e((a), (b))); \ ASSERT_FALSE(e((b), (a))); TEST(StringMapTest, Equals1) { StringMapDefaultEqual e; equalsBothWays("", ""); equalsBothWays("a", "a"); equalsBothWays("bbbbb", "bbbbb"); notEqualsBothWays("", "a"); notEqualsBothWays("a", "b"); notEqualsBothWays("abc", "def"); notEqualsBothWays("abc", "defasdasd"); } TEST(StringMapTest, Basic1) { StringMap m; ASSERT_EQUALS(0U, m.size()); ASSERT_TRUE(m.empty()); m["eliot"] = 5; ASSERT_EQUALS(5, m["eliot"]); ASSERT_EQUALS(1U, m.size()); ASSERT_FALSE(m.empty()); } TEST(StringMapTest, Big1) { StringMap m; char buf[64]; for (int i = 0; i < 10000; i++) { sprintf(buf, "foo%d", i); m[buf] = i; } for (int i = 0; i < 10000; i++) { sprintf(buf, "foo%d", i); ASSERT_EQUALS(m[buf], i); } } TEST(StringMapTest, find1) { StringMap m; ASSERT_TRUE(m.end() == m.find("foo")); m["foo"] = 5; StringMap::const_iterator i = m.find("foo"); ASSERT_TRUE(i != m.end()); ASSERT_EQUALS(5, i->second); ASSERT_EQUALS("foo", i->first); ++i; ASSERT_TRUE(i == m.end()); } TEST(StringMapTest, Erase1) { StringMap m; char buf[64]; m["eliot"] = 5; ASSERT_EQUALS(5, m["eliot"]); ASSERT_EQUALS(1U, m.size()); ASSERT_FALSE(m.empty()); ASSERT_EQUALS(1U, m.erase("eliot")); ASSERT(m.end() == m.find("eliot")); ASSERT_EQUALS(0U, m.size()); ASSERT_TRUE(m.empty()); ASSERT_EQUALS(0, m["eliot"]); ASSERT_EQUALS(1U, m.size()); ASSERT_FALSE(m.empty()); ASSERT_EQUALS(1U, m.erase("eliot")); ASSERT(m.end() == m.find("eliot")); ASSERT_EQUALS(0U, m.erase("eliot")); size_t before = m.capacity(); for (int i = 0; i < 10000; i++) { sprintf(buf, "foo%d", i); m[buf] = i; ASSERT_EQUALS(i, m[buf]); ASSERT_EQUALS(1U, m.erase(buf)); ASSERT(m.end() == m.find(buf)); } ASSERT_EQUALS(before, m.capacity()); } TEST(StringMapTest, Erase2) { StringMap m; m["eliot"] = 5; ASSERT_EQUALS(1U, m.size()); ASSERT_FALSE(m.empty()); StringMap::const_iterator i = m.find("eliot"); ASSERT_EQUALS(5, i->second); m.erase(i); ASSERT_EQUALS(0U, m.size()); ASSERT_TRUE(m.empty()); } TEST(StringMapTest, Iterator1) { StringMap m; ASSERT(m.begin() == m.end()); } TEST(StringMapTest, Iterator2) { StringMap m; m["eliot"] = 5; StringMap::const_iterator i = m.begin(); ASSERT_EQUALS("eliot", i->first); ASSERT_EQUALS(5, i->second); ++i; ASSERT(i == m.end()); } TEST(StringMapTest, Iterator3) { StringMap m; m["eliot"] = 5; m["bob"] = 6; StringMap::const_iterator i = m.begin(); int sum = 0; for (; i != m.end(); ++i) { sum += i->second; } ASSERT_EQUALS(11, sum); } TEST(StringMapTest, Copy1) { StringMap m; m["eliot"] = 5; StringMap y = m; ASSERT_EQUALS(5, y["eliot"]); m["eliot"] = 6; ASSERT_EQUALS(6, m["eliot"]); ASSERT_EQUALS(5, y["eliot"]); } TEST(StringMapTest, Assign) { StringMap m; m["eliot"] = 5; StringMap y; y["eliot"] = 6; ASSERT_EQUALS(6, y["eliot"]); y = m; ASSERT_EQUALS(5, y["eliot"]); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/stringutils.cpp000066400000000000000000000110321273231111400241330ustar00rootroot00000000000000// stringutils.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/stringutils.h" namespace mongo { using std::string; using std::vector; void splitStringDelim(const string& str, vector* res, char delim) { if (str.empty()) return; size_t beg = 0; size_t pos = str.find(delim); while (pos != string::npos) { res->push_back(str.substr(beg, pos - beg)); beg = ++pos; pos = str.find(delim, beg); } res->push_back(str.substr(beg)); } void joinStringDelim(const vector& strs, string* res, char delim) { for (vector::const_iterator it = strs.begin(); it != strs.end(); ++it) { if (it != strs.begin()) res->push_back(delim); res->append(*it); } } LexNumCmp::LexNumCmp(bool lexOnly) : _lexOnly(lexOnly) {} int LexNumCmp::cmp(const StringData& sd1, const StringData& sd2, bool lexOnly) { bool startWord = true; size_t s1 = 0; size_t s2 = 0; while (s1 < sd1.size() && s2 < sd2.size()) { bool d1 = (sd1[s1] == '.'); bool d2 = (sd2[s2] == '.'); if (d1 && !d2) return -1; if (d2 && !d1) return 1; if (d1 && d2) { ++s1; ++s2; startWord = true; continue; } bool p1 = (sd1[s1] == (char)255); bool p2 = (sd2[s2] == (char)255); if (p1 && !p2) return 1; if (p2 && !p1) return -1; if (!lexOnly) { bool n1 = isdigit(sd1[s1]); bool n2 = isdigit(sd2[s2]); if (n1 && n2) { // get rid of leading 0s if (startWord) { while (s1 < sd1.size() && sd1[s1] == '0') s1++; while (s2 < sd2.size() && sd2[s2] == '0') s2++; } size_t e1 = s1; size_t e2 = s2; while (e1 < sd1.size() && isdigit(sd1[e1])) e1++; while (e2 < sd2.size() && isdigit(sd2[e2])) e2++; size_t len1 = e1 - s1; size_t len2 = e2 - s2; int result; // if one is longer than the other, return if (len1 > len2) { return 1; } else if (len2 > len1) { return -1; } // if the lengths are equal, just strcmp else { result = strncmp(sd1.rawData() + s1, sd2.rawData() + s2, len1); if (result) return (result > 0) ? 1 : -1; } // otherwise, the numbers are equal s1 = e1; s2 = e2; startWord = false; continue; } if (n1) return 1; if (n2) return -1; } if (sd1[s1] > sd2[s2]) return 1; if (sd2[s2] > sd1[s1]) return -1; s1++; s2++; startWord = false; } if (s1 < sd1.size() && sd1[s1]) return 1; if (s2 < sd2.size() && sd2[s2]) return -1; return 0; } int LexNumCmp::cmp(const StringData& s1, const StringData& s2) const { return cmp(s1, s2, _lexOnly); } bool LexNumCmp::operator()(const StringData& s1, const StringData& s2) const { return cmp(s1, s2) < 0; } int versionCmp(const StringData rhs, const StringData lhs) { if (rhs == lhs) return 0; // handle "1.2.3-" and "1.2.3-pre" if (rhs.size() < lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') return +1; } else if (rhs.size() > lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') return -1; } return LexNumCmp::cmp(rhs, lhs, false); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/stringutils.h000066400000000000000000000044561273231111400236140ustar00rootroot00000000000000// stringutils.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "mongo/base/string_data.h" namespace mongo { // see also mongoutils/str.h - perhaps move these there? // see also text.h void splitStringDelim(const std::string& str, std::vector* res, char delim); void joinStringDelim(const std::vector& strs, std::string* res, char delim); inline std::string tolowerString(StringData input) { std::string::size_type sz = input.size(); boost::scoped_array line(new char[sz + 1]); char* copy = line.get(); for (std::string::size_type i = 0; i < sz; i++) { char c = input[i]; copy[i] = (char)tolower((int)c); } copy[sz] = 0; return copy; } /** Functor for combining lexical and numeric comparisons. */ class LexNumCmp { public: /** @param lexOnly - compare all characters lexically, including digits. */ LexNumCmp(bool lexOnly); /** * Non numeric characters are compared lexicographically; numeric substrings * are compared numerically; dots separate ordered comparable subunits. * For convenience, character 255 is greater than anything else. * @param lexOnly - compare all characters lexically, including digits. */ static int cmp(const StringData& s1, const StringData& s2, bool lexOnly); int cmp(const StringData& s1, const StringData& s2) const; bool operator()(const StringData& s1, const StringData& s2) const; private: bool _lexOnly; }; // TODO: Sane-ify core string functionality // For now, this needs to be near the LexNumCmp or else int versionCmp(const StringData rhs, const StringData lhs); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/stringutils_test.cpp000066400000000000000000000137721273231111400252070ustar00rootroot00000000000000// stringutils_test.cpp /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/unittest/unittest.h" #include "mongo/util/stringutils.h" #include "mongo/util/hex.h" namespace mongo { using std::string; TEST(Comparison, Basic) { // // Basic version comparison tests with different version string types // // Equal ASSERT(versionCmp("1.2.3", "1.2.3") == 0); // Basic ASSERT(versionCmp("1.2.3", "1.2.4") < 0); ASSERT(versionCmp("1.2.3", "1.2.20") < 0); ASSERT(versionCmp("1.2.3", "1.20.3") < 0); ASSERT(versionCmp("2.2.3", "10.2.3") < 0); // Post-fixed ASSERT(versionCmp("1.2.3", "1.2.3-") > 0); ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0); ASSERT(versionCmp("1.2.3", "1.2.4-") < 0); ASSERT(versionCmp("1.2.3-", "1.2.3") < 0); ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0); } TEST(LexNumCmp, Simple1) { ASSERT_EQUALS(0, LexNumCmp::cmp("a.b.c", "a.b.c", false)); } void assertCmp(int expected, const StringData& s1, const StringData& s2, bool lexOnly = false) { mongo::LexNumCmp cmp(lexOnly); ASSERT_EQUALS(expected, cmp.cmp(s1, s2, lexOnly)); ASSERT_EQUALS(expected, cmp.cmp(s1, s2)); ASSERT_EQUALS(expected < 0, cmp(s1, s2)); } TEST(LexNumCmp, Simple2) { ASSERT(!isdigit((char)255)); assertCmp(0, "a", "a"); assertCmp(-1, "a", "aa"); assertCmp(1, "aa", "a"); assertCmp(-1, "a", "b"); assertCmp(1, "100", "50"); assertCmp(-1, "50", "100"); assertCmp(1, "b", "a"); assertCmp(0, "aa", "aa"); assertCmp(-1, "aa", "ab"); assertCmp(1, "ab", "aa"); assertCmp(1, "0", "a"); assertCmp(1, "a0", "aa"); assertCmp(-1, "a", "0"); assertCmp(-1, "aa", "a0"); assertCmp(0, "0", "0"); assertCmp(0, "10", "10"); assertCmp(-1, "1", "10"); assertCmp(1, "10", "1"); assertCmp(1, "11", "10"); assertCmp(-1, "10", "11"); assertCmp(1, "f11f", "f10f"); assertCmp(-1, "f10f", "f11f"); assertCmp(-1, "f11f", "f111"); assertCmp(1, "f111", "f11f"); assertCmp(-1, "f12f", "f12g"); assertCmp(1, "f12g", "f12f"); assertCmp(1, "aa{", "aab"); assertCmp(-1, "aa{", "aa1"); assertCmp(-1, "a1{", "a11"); assertCmp(1, "a1{a", "a1{"); assertCmp(-1, "a1{", "a1{a"); assertCmp(1, "21", "11"); assertCmp(-1, "11", "21"); assertCmp(-1, "a.0", "a.1"); assertCmp(-1, "a.0.b", "a.1"); assertCmp(-1, "b.", "b.|"); assertCmp(-1, "b.0e", (string("b.") + (char)255).c_str()); assertCmp(-1, "b.", "b.0e"); assertCmp(0, "238947219478347782934718234", "238947219478347782934718234"); assertCmp(0, "000238947219478347782934718234", "238947219478347782934718234"); assertCmp(1, "000238947219478347782934718235", "238947219478347782934718234"); assertCmp(-1, "238947219478347782934718234", "238947219478347782934718234.1"); assertCmp(0, "238", "000238"); assertCmp(0, "002384", "0002384"); assertCmp(0, "00002384", "0002384"); assertCmp(0, "0", "0"); assertCmp(0, "0000", "0"); assertCmp(0, "0", "000"); assertCmp(-1, "0000", "0.0"); assertCmp(1, "2380", "238"); assertCmp(1, "2385", "2384"); assertCmp(1, "2385", "02384"); assertCmp(1, "2385", "002384"); assertCmp(-1, "123.234.4567", "00238"); assertCmp(0, "123.234", "00123.234"); assertCmp(0, "a.123.b", "a.00123.b"); assertCmp(1, "a.123.b", "a.b.00123.b"); assertCmp(-1, "a.00.0", "a.0.1"); assertCmp(0, "01.003.02", "1.3.2"); assertCmp(-1, "1.3.2", "10.300.20"); assertCmp(0, "10.300.20", "000000000000010.0000300.000000020"); assertCmp(0, "0000a", "0a"); assertCmp(-1, "a", "0a"); assertCmp(-1, "000a", "001a"); assertCmp(0, "010a", "0010a"); assertCmp(-1, "a0", "a00"); assertCmp(0, "a.0", "a.00"); assertCmp(-1, "a.b.c.d0", "a.b.c.d00"); assertCmp(1, "a.b.c.0.y", "a.b.c.00.x"); assertCmp(-1, "a", "a-"); assertCmp(1, "a-", "a"); assertCmp(0, "a-", "a-"); assertCmp(-1, "a", "a-c"); assertCmp(1, "a-c", "a"); assertCmp(0, "a-c", "a-c"); assertCmp(1, "a-c.t", "a.t"); assertCmp(-1, "a.t", "a-c.t"); assertCmp(0, "a-c.t", "a-c.t"); assertCmp(1, "ac.t", "a.t"); assertCmp(-1, "a.t", "ac.t"); assertCmp(0, "ac.t", "ac.t"); } TEST(LexNumCmp, LexOnly) { assertCmp(-1, "0", "00", true); assertCmp(1, "1", "01", true); assertCmp(-1, "1", "11", true); assertCmp(1, "2", "11", true); } TEST(LexNumCmp, Substring1) { assertCmp(0, "1234", "1234", false); assertCmp(0, StringData("1234"), StringData("1234"), false); assertCmp(0, StringData("1234", 4), StringData("1234", 4), false); assertCmp(-1, StringData("123", 3), StringData("1234", 4), false); assertCmp(0, StringData("0001", 3), StringData("0000", 3), false); } TEST(IntegerToHex, VariousConversions) { ASSERT_EQUALS(std::string("0"), integerToHex(0)); ASSERT_EQUALS(std::string("1"), integerToHex(1)); ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337)); ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111)); ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324)); ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits::min())); ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits::max())); ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"), integerToHex(std::numeric_limits::max())); ASSERT_EQUALS(std::string("8000000000000000"), integerToHex(std::numeric_limits::min())); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/text.cpp000066400000000000000000000326741273231111400225470ustar00rootroot00000000000000// text.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/text.h" #include #include #include #include #include #ifdef _WIN32 #include #endif #include "mongo/platform/basic.h" #include "mongo/util/mongoutils/str.h" using namespace std; namespace mongo { // --- StringSplitter ---- /** get next split string fragment */ string StringSplitter::next() { const char* foo = strstr(_big, _splitter); if (foo) { string s(_big, foo - _big); _big = foo + strlen(_splitter); while (*_big && strstr(_big, _splitter) == _big) _big++; return s; } string s = _big; _big += strlen(_big); return s; } void StringSplitter::split(vector& l) { while (more()) { l.push_back(next()); } } vector StringSplitter::split() { vector l; split(l); return l; } string StringSplitter::join(const vector& l, const string& split) { stringstream ss; for (unsigned i = 0; i < l.size(); i++) { if (i > 0) ss << split; ss << l[i]; } return ss.str(); } vector StringSplitter::split(const string& big, const string& splitter) { StringSplitter ss(big.c_str(), splitter.c_str()); return ss.split(); } // --- utf8 utils ------ inline int leadingOnes(unsigned char c) { if (c < 0x80) return 0; static const char _leadingOnes[128] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 - 0x8F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 0x99 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xA0 - 0xA9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xB0 - 0xB9 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xC0 - 0xC9 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xD0 - 0xD9 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE0 - 0xE9 4, 4, 4, 4, 4, 4, 4, 4, // 0xF0 - 0xF7 5, 5, 5, 5, // 0xF8 - 0xFB 6, 6, // 0xFC - 0xFD 7, // 0xFE 8, // 0xFF }; return _leadingOnes[c & 0x7f]; } bool isValidUTF8(const std::string& s) { return isValidUTF8(s.c_str()); } bool isValidUTF8(const char* s) { int left = 0; // how many bytes are left in the current codepoint while (*s) { const unsigned char c = (unsigned char)*(s++); const int ones = leadingOnes(c); if (left) { if (ones != 1) return false; // should be a continuation byte left--; } else { if (ones == 0) continue; // ASCII byte if (ones == 1) return false; // unexpected continuation byte if (c > 0xF4) return false; // codepoint too large (< 0x10FFFF) if (c == 0xC0 || c == 0xC1) return false; // codepoints <= 0x7F shouldn't be 2 bytes // still valid left = ones - 1; } } if (left != 0) return false; // string ended mid-codepoint return true; } long long parseLL(const char* n) { long long ret; uassert(13307, "cannot convert empty string to long long", *n != 0); #if !defined(_WIN32) char* endPtr = 0; errno = 0; ret = strtoll(n, &endPtr, 10); uassert(13305, "could not convert string to long long", *endPtr == 0 && errno == 0); #elif _MSC_VER >= 1600 // 1600 is VS2k10 1500 is VS2k8 size_t endLen = 0; try { ret = stoll(n, &endLen, 10); } catch (...) { endLen = 0; } uassert(13306, "could not convert string to long long", endLen != 0 && n[endLen] == 0); #else // stoll() wasn't introduced until VS 2010. char* endPtr = 0; ret = _strtoi64(n, &endPtr, 10); uassert(13310, "could not convert string to long long", (*endPtr == 0) && (ret != _I64_MAX) && (ret != _I64_MIN)); #endif // !defined(_WIN32) return ret; } #if defined(_WIN32) std::string toUtf8String(const std::wstring& wide) { if (wide.size() > boost::integer_traits::const_max) throw std::length_error("Wide string cannot be more than INT_MAX characters long."); if (wide.size() == 0) return ""; // Calculate necessary buffer size int len = ::WideCharToMultiByte( CP_UTF8, 0, wide.c_str(), static_cast(wide.size()), NULL, 0, NULL, NULL); // Perform actual conversion if (len > 0) { std::vector buffer(len); len = ::WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), static_cast(wide.size()), &buffer[0], static_cast(buffer.size()), NULL, NULL); if (len > 0) { verify(len == static_cast(buffer.size())); return std::string(&buffer[0], buffer.size()); } } msgasserted(16091, mongoutils::str::stream() << "can't wstring to utf8: " << ::GetLastError()); return ""; } std::wstring toWideString(const char* utf8String) { int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page 0, // Flags utf8String, // Input string -1, // Count, -1 for NUL-terminated NULL, // No output buffer 0 // Zero means "compute required size" ); if (bufferSize == 0) { return std::wstring(); } boost::scoped_array tempBuffer(new wchar_t[bufferSize]); tempBuffer[0] = 0; MultiByteToWideChar(CP_UTF8, // Code page 0, // Flags utf8String, // Input string -1, // Count, -1 for NUL-terminated tempBuffer.get(), // UTF-16 output buffer bufferSize // Buffer size in wide characters ); return std::wstring(tempBuffer.get()); } /** * Write a UTF-8 string to the Windows console in Unicode (UTF-16) * * @param utf8String UTF-8 input string * @param utf8StringSize Number of bytes in UTF-8 string, no NUL terminator assumed * @return true if all characters were displayed (including zero characters) */ bool writeUtf8ToWindowsConsole(const char* utf8String, unsigned int utf8StringSize) { int bufferSize = MultiByteToWideChar(CP_UTF8, // Code page 0, // Flags utf8String, // Input string utf8StringSize, // Input string length NULL, // No output buffer 0 // Zero means "compute required size" ); if (bufferSize == 0) { return true; } boost::scoped_array utf16String(new wchar_t[bufferSize]); MultiByteToWideChar(CP_UTF8, // Code page 0, // Flags utf8String, // Input string utf8StringSize, // Input string length utf16String.get(), // UTF-16 output buffer bufferSize // Buffer size in wide characters ); const wchar_t* utf16Pointer = utf16String.get(); size_t numberOfCharactersToWrite = bufferSize; HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); while (numberOfCharactersToWrite > 0) { static const DWORD MAXIMUM_CHARACTERS_PER_PASS = 8 * 1024; DWORD numberOfCharactersThisPass = static_cast(numberOfCharactersToWrite); if (numberOfCharactersThisPass > MAXIMUM_CHARACTERS_PER_PASS) { numberOfCharactersThisPass = MAXIMUM_CHARACTERS_PER_PASS; } DWORD numberOfCharactersWritten; BOOL success = WriteConsoleW(consoleHandle, utf16Pointer, numberOfCharactersThisPass, &numberOfCharactersWritten, NULL); if (0 == success) { DWORD dosError = GetLastError(); static bool errorMessageShown = false; if (ERROR_GEN_FAILURE == dosError) { if (!errorMessageShown) { std::cout << "\n---\nUnicode text could not be correctly displayed.\n" "Please change your console font to a Unicode font " "(e.g. Lucida Console).\n---\n" << std::endl; errorMessageShown = true; } // we can't display the text properly using a raster font, // but we can display the bits that will display ... _write(1, utf8String, utf8StringSize); } return false; } numberOfCharactersToWrite -= numberOfCharactersWritten; utf16Pointer += numberOfCharactersWritten; } return true; } WindowsCommandLine::WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]) : _argv(NULL), _envp(NULL) { // Construct UTF-8 copy of arguments vector utf8args; vector utf8argLength; size_t blockSize = argc * sizeof(char*); size_t blockPtr = blockSize; for (int i = 0; i < argc; ++i) { utf8args.push_back(toUtf8String(argvW[i])); size_t argLength = utf8args[i].length() + 1; utf8argLength.push_back(argLength); blockSize += argLength; } _argv = static_cast(malloc(blockSize)); for (int i = 0; i < argc; ++i) { _argv[i] = reinterpret_cast(_argv) + blockPtr; strcpy_s(_argv[i], utf8argLength[i], utf8args[i].c_str()); blockPtr += utf8argLength[i]; } // Construct UTF-8 copy of environment strings size_t envCount = 0; wchar_t** envpWptr = &envpW[0]; while (*envpWptr++) { ++envCount; } vector utf8envs; vector utf8envLength; blockSize = (envCount + 1) * sizeof(char*); blockPtr = blockSize; for (size_t i = 0; i < envCount; ++i) { utf8envs.push_back(toUtf8String(envpW[i])); size_t envLength = utf8envs[i].length() + 1; utf8envLength.push_back(envLength); blockSize += envLength; } _envp = static_cast(malloc(blockSize)); size_t i; for (i = 0; i < envCount; ++i) { _envp[i] = reinterpret_cast(_envp) + blockPtr; strcpy_s(_envp[i], utf8envLength[i], utf8envs[i].c_str()); blockPtr += utf8envLength[i]; } _envp[i] = NULL; } WindowsCommandLine::~WindowsCommandLine() { free(_argv); free(_envp); } #endif // #if defined(_WIN32) // See "Parsing C++ Command-Line Arguments (C++)" // http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx static void quoteForWindowsCommandLine(const std::string& arg, std::ostream& os) { if (arg.empty()) { os << "\"\""; } else if (arg.find_first_of(" \t\"") == std::string::npos) { os << arg; } else { os << '"'; std::string backslashes = ""; for (std::string::const_iterator iter = arg.begin(), end = arg.end(); iter != end; ++iter) { switch (*iter) { case '\\': backslashes.push_back(*iter); if (iter + 1 == end) os << backslashes << backslashes; break; case '"': os << backslashes << backslashes << "\\\""; break; default: os << backslashes << *iter; backslashes.clear(); break; } } os << '"'; } } std::string constructUtf8WindowsCommandLine(const std::vector& argv) { if (argv.empty()) return ""; std::ostringstream commandLine; std::vector::const_iterator iter = argv.begin(); std::vector::const_iterator end = argv.end(); quoteForWindowsCommandLine(*iter, commandLine); ++iter; for (; iter != end; ++iter) { commandLine << ' '; quoteForWindowsCommandLine(*iter, commandLine); } return commandLine.str(); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/util/text.h000066400000000000000000000060121273231111400221770ustar00rootroot00000000000000// text.h /* * Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "mongo/base/disallow_copying.h" namespace mongo { class StringSplitter { public: /** @param big the string to be split @param splitter the delimiter */ StringSplitter(const char* big, const char* splitter) : _big(big), _splitter(splitter) {} /** @return true if more to be taken via next() */ bool more() const { return _big[0] != 0; } /** get next split string fragment */ std::string next(); void split(std::vector& l); std::vector split(); static std::vector split(const std::string& big, const std::string& splitter); static std::string join(const std::vector& l, const std::string& split); private: const char* _big; const char* _splitter; }; /* This doesn't defend against ALL bad UTF8, but it will guarantee that the * string can be converted to sequence of codepoints. However, it doesn't * guarantee that the codepoints are valid. */ bool isValidUTF8(const char* s); bool isValidUTF8(const std::string& s); // expect that n contains a base ten number and nothing else after it // NOTE win version hasn't been tested directly long long parseLL(const char* n); #if defined(_WIN32) std::string toUtf8String(const std::wstring& wide); std::wstring toWideString(const char* s); bool writeUtf8ToWindowsConsole(const char* utf8String, unsigned int utf8StringSize); /* like toWideString but UNICODE macro sensitive */ #if !defined(_UNICODE) #error temp error inline std::string toNativeString(const char* s) { return s; } #else inline std::wstring toNativeString(const char* s) { return toWideString(s); } #endif class WindowsCommandLine { MONGO_DISALLOW_COPYING(WindowsCommandLine); char** _argv; char** _envp; public: WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]); ~WindowsCommandLine(); char** argv(void) const { return _argv; }; char** envp(void) const { return _envp; }; }; #endif // #if defined(_WIN32) /** * Construct a Windows command line string, UTF-8 encoded, from a vector of * UTF-8 arguments, "argv". * * See "Parsing C++ Command-Line Arguments (C++)" * http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx */ std::string constructUtf8WindowsCommandLine(const std::vector& argv); } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/time_support.cpp000066400000000000000000000777341273231111400243230ustar00rootroot00000000000000/* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/time_support.h" #include #include #include #include #include #include #include "mongo/base/init.h" #include "mongo/base/parse_number.h" #include "mongo/bson/util/builder.h" #include "mongo/platform/cstdint.h" #include "mongo/util/debug_util.h" #include "mongo/util/assert_util.h" #ifdef _WIN32 #include #include #include "mongo/util/timer.h" // NOTE(schwerin): MSVC's _snprintf is not a drop-in replacement for C99's snprintf(). In // particular, when the target buffer is too small, behaviors differ. Consult the documentation // from MSDN and form the BSD or Linux man pages before using. #define snprintf _snprintf #endif #if !defined(_WIN32) && !defined(MONGO_HAVE_TIMEGM) // Not all systems have timegm defined (it isn't part of POSIX), so fall back to our vendored // implementation if our configure checks did not detect it as available on the current // system. See SERVER-13446, SERVER-14019, and CXX-204. extern "C" time_t timegm(struct tm* const tmp); #endif namespace mongo { bool Date_t::isFormatable() const { if (sizeof(time_t) == sizeof(int32_t)) { return millis < 2147483647000ULL; // "2038-01-19T03:14:07Z" } else { return millis < 32535215999000ULL; // "3000-12-31T23:59:59Z" } } // jsTime_virtual_skew is just for testing. a test command manipulates it. long long jsTime_virtual_skew = 0; boost::thread_specific_ptr jsTime_virtual_thread_skew; using std::string; void time_t_to_Struct(time_t t, struct tm* buf, bool local) { #if defined(_WIN32) if (local) localtime_s(buf, &t); else gmtime_s(buf, &t); #else if (local) localtime_r(&t, buf); else gmtime_r(&t, buf); #endif } std::string time_t_to_String(time_t t) { char buf[64]; #if defined(_WIN32) ctime_s(buf, sizeof(buf), &t); #else ctime_r(&t, buf); #endif buf[24] = 0; // don't want the \n return buf; } std::string time_t_to_String_short(time_t t) { char buf[64]; #if defined(_WIN32) ctime_s(buf, sizeof(buf), &t); #else ctime_r(&t, buf); #endif buf[19] = 0; if (buf[0] && buf[1] && buf[2] && buf[3]) return buf + 4; // skip day of week return buf; } // uses ISO 8601 dates without trailing Z // colonsOk should be false when creating filenames string terseCurrentTime(bool colonsOk) { struct tm t; time_t_to_Struct(time(0), &t); const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M-%S"); char buf[32]; fassert(16226, strftime(buf, sizeof(buf), fmt, &t) == 19); return buf; } #define MONGO_ISO_DATE_FMT_NO_TZ "%Y-%m-%dT%H:%M:%S" string timeToISOString(time_t time) { struct tm t; time_t_to_Struct(time, &t); const char* fmt = MONGO_ISO_DATE_FMT_NO_TZ "Z"; char buf[32]; fassert(16227, strftime(buf, sizeof(buf), fmt, &t) == 20); return buf; } namespace { struct DateStringBuffer { static const int dataCapacity = 64; char data[dataCapacity]; int size; }; void _dateToISOString(Date_t date, bool local, DateStringBuffer* result) { invariant(date.isFormatable()); static const int bufSize = DateStringBuffer::dataCapacity; char* const buf = result->data; struct tm t; time_t_to_Struct(date.toTimeT(), &t, local); int pos = strftime(buf, bufSize, MONGO_ISO_DATE_FMT_NO_TZ, &t); dassert(0 < pos); char* cur = buf + pos; int bufRemaining = bufSize - pos; pos = snprintf(cur, bufRemaining, ".%03d", static_cast(date.asInt64() % 1000)); dassert(bufRemaining > pos && pos > 0); cur += pos; bufRemaining -= pos; if (local) { static const int localTzSubstrLen = 5; dassert(bufRemaining >= localTzSubstrLen + 1); #ifdef _WIN32 // NOTE(schwerin): The value stored by _get_timezone is the value one adds to local time // to get UTC. This is opposite of the ISO-8601 meaning of the timezone offset. // NOTE(schwerin): Microsoft's timezone code always assumes US rules for daylight // savings time. We can do no better without completely reimplementing localtime_s and // related time library functions. long msTimeZone; _get_timezone(&msTimeZone); if (t.tm_isdst) msTimeZone -= 3600; const bool tzIsWestOfUTC = msTimeZone > 0; const long tzOffsetSeconds = msTimeZone * (tzIsWestOfUTC ? 1 : -1); const long tzOffsetHoursPart = tzOffsetSeconds / 3600; const long tzOffsetMinutesPart = (tzOffsetSeconds / 60) % 60; snprintf(cur, localTzSubstrLen + 1, "%c%02ld%02ld", tzIsWestOfUTC ? '-' : '+', tzOffsetHoursPart, tzOffsetMinutesPart); #else strftime(cur, bufRemaining, "%z", &t); #endif cur += localTzSubstrLen; } else { dassert(bufRemaining >= 2); *cur = 'Z'; ++cur; } result->size = cur - buf; dassert(result->size < DateStringBuffer::dataCapacity); } void _dateToCtimeString(Date_t date, DateStringBuffer* result) { static const size_t ctimeSubstrLen = 19; static const size_t millisSubstrLen = 4; time_t t = date.toTimeT(); #if defined(_WIN32) ctime_s(result->data, sizeof(result->data), &t); #else ctime_r(&t, result->data); #endif char* milliSecStr = result->data + ctimeSubstrLen; snprintf( milliSecStr, millisSubstrLen + 1, ".%03d", static_cast(date.asInt64() % 1000)); result->size = ctimeSubstrLen + millisSubstrLen; } } // namespace std::string dateToISOStringUTC(Date_t date) { DateStringBuffer buf; _dateToISOString(date, false, &buf); return std::string(buf.data, buf.size); } std::string dateToISOStringLocal(Date_t date) { DateStringBuffer buf; _dateToISOString(date, true, &buf); return std::string(buf.data, buf.size); } std::string dateToCtimeString(Date_t date) { DateStringBuffer buf; _dateToCtimeString(date, &buf); return std::string(buf.data, buf.size); } void outputDateAsISOStringUTC(std::ostream& os, Date_t date) { DateStringBuffer buf; _dateToISOString(date, false, &buf); os << StringData(buf.data, buf.size); } void outputDateAsISOStringLocal(std::ostream& os, Date_t date) { DateStringBuffer buf; _dateToISOString(date, true, &buf); os << StringData(buf.data, buf.size); } void outputDateAsCtime(std::ostream& os, Date_t date) { DateStringBuffer buf; _dateToCtimeString(date, &buf); os << StringData(buf.data, buf.size); } namespace { StringData getNextToken(const StringData& currentString, const StringData& terminalChars, size_t startIndex, size_t* endIndex) { size_t index = startIndex; if (index == std::string::npos) { *endIndex = std::string::npos; return StringData(); } for (; index < currentString.size(); index++) { if (terminalChars.find(currentString[index]) != std::string::npos) { break; } } // substr just returns the rest of the string if the length passed in is greater than the // number of characters remaining, and since std::string::npos is the length of the largest // possible string we know (std::string::npos - startIndex) is at least as long as the rest // of the string. That means this handles both the case where we hit a terminating // character and we want a substring, and the case where didn't and just want the rest of // the string. *endIndex = (index < currentString.size() ? index : std::string::npos); return currentString.substr(startIndex, index - startIndex); } // Check to make sure that the string only consists of digits bool isOnlyDigits(const StringData& toCheck) { StringData digits("0123456789"); for (StringData::const_iterator iterator = toCheck.begin(); iterator != toCheck.end(); iterator++) { if (digits.find(*iterator) == std::string::npos) { return false; } } return true; } Status parseTimeZoneFromToken(const StringData& tzStr, int* tzAdjSecs) { *tzAdjSecs = 0; if (!tzStr.empty()) { if (tzStr[0] == 'Z') { if (tzStr.size() != 1) { StringBuilder sb; sb << "Found trailing characters in time zone specifier: " << tzStr; return Status(ErrorCodes::BadValue, sb.str()); } } else if (tzStr[0] == '+' || tzStr[0] == '-') { if (tzStr.size() != 5 || !isOnlyDigits(tzStr.substr(1, 4))) { StringBuilder sb; sb << "Time zone adjustment string should be four digits: " << tzStr; return Status(ErrorCodes::BadValue, sb.str()); } // Parse the hours component of the time zone offset. Note that // parseNumberFromStringWithBase correctly handles the sign bit, so leave that in. StringData tzHoursStr = tzStr.substr(0, 3); int tzAdjHours = 0; Status status = parseNumberFromStringWithBase(tzHoursStr, 10, &tzAdjHours); if (!status.isOK()) { return status; } if (tzAdjHours < -23 || tzAdjHours > 23) { StringBuilder sb; sb << "Time zone hours adjustment out of range: " << tzAdjHours; return Status(ErrorCodes::BadValue, sb.str()); } StringData tzMinutesStr = tzStr.substr(3, 2); int tzAdjMinutes = 0; status = parseNumberFromStringWithBase(tzMinutesStr, 10, &tzAdjMinutes); if (!status.isOK()) { return status; } if (tzAdjMinutes < 0 || tzAdjMinutes > 59) { StringBuilder sb; sb << "Time zone minutes adjustment out of range: " << tzAdjMinutes; return Status(ErrorCodes::BadValue, sb.str()); } // Use the sign that parseNumberFromStringWithBase found to determine if we need to // flip the sign of our minutes component. Also, we need to flip the sign of our // final result, because the offset passed in by the user represents how far off the // time they are giving us is from UTC, which means that we have to go the opposite // way to compensate and get the UTC time *tzAdjSecs = (-1) * ((tzAdjHours < 0 ? -1 : 1) * (tzAdjMinutes * 60) + (tzAdjHours * 60 * 60)); // Disallow adjustiment of 24 hours or more in either direction (should be checked // above as the separate components of minutes and hours) fassert(17318, *tzAdjSecs > -86400 && *tzAdjSecs < 86400); } else { StringBuilder sb; sb << "Invalid time zone string: \"" << tzStr << "\". Found invalid character at the beginning of time " << "zone specifier: " << tzStr[0]; return Status(ErrorCodes::BadValue, sb.str()); } } else { return Status(ErrorCodes::BadValue, "Missing required time zone specifier for date"); } return Status::OK(); } Status parseMillisFromToken(const StringData& millisStr, int* resultMillis) { *resultMillis = 0; if (!millisStr.empty()) { if (millisStr.size() > 3 || !isOnlyDigits(millisStr)) { StringBuilder sb; sb << "Millisecond string should be at most three digits: " << millisStr; return Status(ErrorCodes::BadValue, sb.str()); } Status status = parseNumberFromStringWithBase(millisStr, 10, resultMillis); if (!status.isOK()) { return status; } // Treat the digits differently depending on how many there are. 1 digit = hundreds of // milliseconds, 2 digits = tens of milliseconds, 3 digits = milliseconds. int millisMagnitude = 1; if (millisStr.size() == 2) { millisMagnitude = 10; } else if (millisStr.size() == 1) { millisMagnitude = 100; } *resultMillis = *resultMillis* millisMagnitude; if (*resultMillis < 0 || *resultMillis > 1000) { StringBuilder sb; sb << "Millisecond out of range: " << *resultMillis; return Status(ErrorCodes::BadValue, sb.str()); } } return Status::OK(); } Status parseTmFromTokens(const StringData& yearStr, const StringData& monthStr, const StringData& dayStr, const StringData& hourStr, const StringData& minStr, const StringData& secStr, std::tm* resultTm) { memset(resultTm, 0, sizeof(*resultTm)); // Parse year if (yearStr.size() != 4 || !isOnlyDigits(yearStr)) { StringBuilder sb; sb << "Year string should be four digits: " << yearStr; return Status(ErrorCodes::BadValue, sb.str()); } Status status = parseNumberFromStringWithBase(yearStr, 10, &resultTm->tm_year); if (!status.isOK()) { return status; } if (resultTm->tm_year < 1970 || resultTm->tm_year > 9999) { StringBuilder sb; sb << "Year out of range: " << resultTm->tm_year; return Status(ErrorCodes::BadValue, sb.str()); } resultTm->tm_year -= 1900; // Parse month if (monthStr.size() != 2 || !isOnlyDigits(monthStr)) { StringBuilder sb; sb << "Month string should be two digits: " << monthStr; return Status(ErrorCodes::BadValue, sb.str()); } status = parseNumberFromStringWithBase(monthStr, 10, &resultTm->tm_mon); if (!status.isOK()) { return status; } if (resultTm->tm_mon < 1 || resultTm->tm_mon > 12) { StringBuilder sb; sb << "Month out of range: " << resultTm->tm_mon; return Status(ErrorCodes::BadValue, sb.str()); } resultTm->tm_mon -= 1; // Parse day if (dayStr.size() != 2 || !isOnlyDigits(dayStr)) { StringBuilder sb; sb << "Day string should be two digits: " << dayStr; return Status(ErrorCodes::BadValue, sb.str()); } status = parseNumberFromStringWithBase(dayStr, 10, &resultTm->tm_mday); if (!status.isOK()) { return status; } if (resultTm->tm_mday < 1 || resultTm->tm_mday > 31) { StringBuilder sb; sb << "Day out of range: " << resultTm->tm_mday; return Status(ErrorCodes::BadValue, sb.str()); } // Parse hour if (hourStr.size() != 2 || !isOnlyDigits(hourStr)) { StringBuilder sb; sb << "Hour string should be two digits: " << hourStr; return Status(ErrorCodes::BadValue, sb.str()); } status = parseNumberFromStringWithBase(hourStr, 10, &resultTm->tm_hour); if (!status.isOK()) { return status; } if (resultTm->tm_hour < 0 || resultTm->tm_hour > 23) { StringBuilder sb; sb << "Hour out of range: " << resultTm->tm_hour; return Status(ErrorCodes::BadValue, sb.str()); } // Parse minute if (minStr.size() != 2 || !isOnlyDigits(minStr)) { StringBuilder sb; sb << "Minute string should be two digits: " << minStr; return Status(ErrorCodes::BadValue, sb.str()); } status = parseNumberFromStringWithBase(minStr, 10, &resultTm->tm_min); if (!status.isOK()) { return status; } if (resultTm->tm_min < 0 || resultTm->tm_min > 59) { StringBuilder sb; sb << "Minute out of range: " << resultTm->tm_min; return Status(ErrorCodes::BadValue, sb.str()); } // Parse second if it exists if (secStr.empty()) { return Status::OK(); } if (secStr.size() != 2 || !isOnlyDigits(secStr)) { StringBuilder sb; sb << "Second string should be two digits: " << secStr; return Status(ErrorCodes::BadValue, sb.str()); } status = parseNumberFromStringWithBase(secStr, 10, &resultTm->tm_sec); if (!status.isOK()) { return status; } if (resultTm->tm_sec < 0 || resultTm->tm_sec > 59) { StringBuilder sb; sb << "Second out of range: " << resultTm->tm_sec; return Status(ErrorCodes::BadValue, sb.str()); } return Status::OK(); } Status parseTm(const StringData& dateString, std::tm* resultTm, int* resultMillis, int* tzAdjSecs) { size_t yearEnd = std::string::npos; size_t monthEnd = std::string::npos; size_t dayEnd = std::string::npos; size_t hourEnd = std::string::npos; size_t minEnd = std::string::npos; size_t secEnd = std::string::npos; size_t millisEnd = std::string::npos; size_t tzEnd = std::string::npos; StringData yearStr, monthStr, dayStr, hourStr, minStr, secStr, millisStr, tzStr; yearStr = getNextToken(dateString, "-", 0, &yearEnd); monthStr = getNextToken(dateString, "-", yearEnd + 1, &monthEnd); dayStr = getNextToken(dateString, "T", monthEnd + 1, &dayEnd); hourStr = getNextToken(dateString, ":", dayEnd + 1, &hourEnd); minStr = getNextToken(dateString, ":+-Z", hourEnd + 1, &minEnd); // Only look for seconds if the character we matched for the end of the minutes token is a // colon if (minEnd != std::string::npos && dateString[minEnd] == ':') { // Make sure the string doesn't end with ":" if (minEnd == dateString.size() - 1) { StringBuilder sb; sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[minEnd] << "\" character"; return Status(ErrorCodes::BadValue, sb.str()); } secStr = getNextToken(dateString, ".+-Z", minEnd + 1, &secEnd); // Make sure we actually got something for seconds, since here we know they are expected if (secStr.empty()) { StringBuilder sb; sb << "Missing seconds in date: " << dateString; return Status(ErrorCodes::BadValue, sb.str()); } } // Only look for milliseconds if the character we matched for the end of the seconds token // is a period if (secEnd != std::string::npos && dateString[secEnd] == '.') { // Make sure the string doesn't end with "." if (secEnd == dateString.size() - 1) { StringBuilder sb; sb << "Invalid date: " << dateString << ". Ends with \"" << dateString[secEnd] << "\" character"; return Status(ErrorCodes::BadValue, sb.str()); } millisStr = getNextToken(dateString, "+-Z", secEnd + 1, &millisEnd); // Make sure we actually got something for millis, since here we know they are expected if (millisStr.empty()) { StringBuilder sb; sb << "Missing seconds in date: " << dateString; return Status(ErrorCodes::BadValue, sb.str()); } } // Now look for the time zone specifier depending on which prefix of the time we provided if (millisEnd != std::string::npos) { tzStr = getNextToken(dateString, "", millisEnd, &tzEnd); } else if (secEnd != std::string::npos && dateString[secEnd] != '.') { tzStr = getNextToken(dateString, "", secEnd, &tzEnd); } else if (minEnd != std::string::npos && dateString[minEnd] != ':') { tzStr = getNextToken(dateString, "", minEnd, &tzEnd); } Status status = parseTmFromTokens(yearStr, monthStr, dayStr, hourStr, minStr, secStr, resultTm); if (!status.isOK()) { return status; } status = parseTimeZoneFromToken(tzStr, tzAdjSecs); if (!status.isOK()) { return status; } status = parseMillisFromToken(millisStr, resultMillis); if (!status.isOK()) { return status; } return Status::OK(); } } // namespace StatusWith dateFromISOString(const StringData& dateString) { std::tm theTime; int millis = 0; int tzAdjSecs = 0; Status status = parseTm(dateString, &theTime, &millis, &tzAdjSecs); if (!status.isOK()) { return StatusWith(ErrorCodes::BadValue, status.reason()); } unsigned long long resultMillis = 0; #if defined(_WIN32) SYSTEMTIME dateStruct; dateStruct.wMilliseconds = millis; dateStruct.wSecond = theTime.tm_sec; dateStruct.wMinute = theTime.tm_min; dateStruct.wHour = theTime.tm_hour; dateStruct.wDay = theTime.tm_mday; dateStruct.wDayOfWeek = -1; /* ignored */ dateStruct.wMonth = theTime.tm_mon + 1; dateStruct.wYear = theTime.tm_year + 1900; // Output parameter for SystemTimeToFileTime FILETIME fileTime; // the wDayOfWeek member of SYSTEMTIME is ignored by this function if (SystemTimeToFileTime(&dateStruct, &fileTime) == 0) { StringBuilder sb; sb << "Error converting Windows system time to file time for date: " << dateString << ". Error code: " << GetLastError(); return StatusWith(ErrorCodes::BadValue, sb.str()); } // The Windows FILETIME structure contains two parts of a 64-bit value representing the // number of 100-nanosecond intervals since January 1, 1601 unsigned long long windowsTimeOffset = (static_cast(fileTime.dwHighDateTime) << 32) | fileTime.dwLowDateTime; // There are 11644473600 seconds between the unix epoch and the windows epoch // 100-nanoseconds = milliseconds * 10000 unsigned long long epochDifference = 11644473600000 * 10000; // removes the diff between 1970 and 1601 windowsTimeOffset -= epochDifference; // 1 milliseconds = 1000000 nanoseconds = 10000 100-nanosecond intervals resultMillis = windowsTimeOffset / 10000; #else struct tm dateStruct = {0}; dateStruct.tm_sec = theTime.tm_sec; dateStruct.tm_min = theTime.tm_min; dateStruct.tm_hour = theTime.tm_hour; dateStruct.tm_mday = theTime.tm_mday; dateStruct.tm_mon = theTime.tm_mon; dateStruct.tm_year = theTime.tm_year; dateStruct.tm_wday = 0; dateStruct.tm_yday = 0; resultMillis = (1000 * static_cast(timegm(&dateStruct))) + millis; #endif resultMillis += (tzAdjSecs * 1000); return StatusWith(resultMillis); } #undef MONGO_ISO_DATE_FMT_NO_TZ void Date_t::toTm(tm* buf) { time_t dtime = toTimeT(); #if defined(_WIN32) gmtime_s(buf, &dtime); #else gmtime_r(&dtime, buf); #endif } std::string Date_t::toString() const { return time_t_to_String(toTimeT()); } time_t Date_t::toTimeT() const { verify((long long)millis >= 0); // TODO when millis is signed, delete verify(((long long)millis / 1000) < (std::numeric_limits::max)()); return millis / 1000; } boost::gregorian::date currentDate() { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); return now.date(); } // parses time of day in "hh:mm" format assuming 'hh' is 00-23 bool toPointInTime(const string& str, boost::posix_time::ptime* timeOfDay) { int hh = 0; int mm = 0; if (2 != sscanf(str.c_str(), "%d:%d", &hh, &mm)) { return false; } // verify that time is well formed if ((hh / 24) || (mm / 60)) { return false; } boost::posix_time::ptime res(currentDate(), boost::posix_time::hours(hh) + boost::posix_time::minutes(mm)); *timeOfDay = res; return true; } #if defined(_WIN32) void sleepsecs(int s) { Sleep(s * 1000); } void sleepmillis(long long s) { fassert(16228, s <= 0xffffffff); Sleep((DWORD)s); } void sleepmicros(long long s) { if (s <= 0) return; boost::xtime xt; boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC); xt.sec += (int)(s / 1000000); xt.nsec += (int)((s % 1000000) * 1000); if (xt.nsec >= 1000000000) { xt.nsec -= 1000000000; xt.sec++; } boost::thread::sleep(xt); } #else void sleepsecs(int s) { struct timespec t; t.tv_sec = s; t.tv_nsec = 0; if (nanosleep(&t, 0)) { std::cout << "nanosleep failed" << std::endl; } } void sleepmicros(long long s) { if (s <= 0) return; struct timespec t; t.tv_sec = (int)(s / 1000000); t.tv_nsec = 1000 * (s % 1000000); struct timespec out; if (nanosleep(&t, &out)) { std::cout << "nanosleep failed" << std::endl; } } void sleepmillis(long long s) { sleepmicros(s * 1000); } #endif void Backoff::nextSleepMillis() { // Get the current time unsigned long long currTimeMillis = curTimeMillis64(); int lastSleepMillis = _lastSleepMillis; if (_lastErrorTimeMillis == 0 || _lastErrorTimeMillis > currTimeMillis /* VM bugs exist */) _lastErrorTimeMillis = currTimeMillis; unsigned long long lastErrorTimeMillis = _lastErrorTimeMillis; _lastErrorTimeMillis = currTimeMillis; lastSleepMillis = getNextSleepMillis(lastSleepMillis, currTimeMillis, lastErrorTimeMillis); // Store the last slept time _lastSleepMillis = lastSleepMillis; sleepmillis(lastSleepMillis); } int Backoff::getNextSleepMillis(int lastSleepMillis, unsigned long long currTimeMillis, unsigned long long lastErrorTimeMillis) const { // Backoff logic // Get the time since the last error unsigned long long timeSinceLastErrorMillis = currTimeMillis - lastErrorTimeMillis; // Makes the cast below safe verify(_resetAfterMillis >= 0); // If we haven't seen another error recently (3x the max wait time), reset our // wait counter. if (timeSinceLastErrorMillis > (unsigned)(_resetAfterMillis)) lastSleepMillis = 0; // Makes the test below sane verify(_maxSleepMillis > 0); // Wait a power of two millis if (lastSleepMillis == 0) lastSleepMillis = 1; else lastSleepMillis = std::min(lastSleepMillis * 2, _maxSleepMillis); return lastSleepMillis; } extern long long jsTime_virtual_skew; extern boost::thread_specific_ptr jsTime_virtual_thread_skew; // DO NOT TOUCH except for testing void jsTimeVirtualSkew(long long skew) { jsTime_virtual_skew = skew; } long long getJSTimeVirtualSkew() { return jsTime_virtual_skew; } void jsTimeVirtualThreadSkew(long long skew) { jsTime_virtual_thread_skew.reset(new long long(skew)); } long long getJSTimeVirtualThreadSkew() { if (jsTime_virtual_thread_skew.get()) { return *(jsTime_virtual_thread_skew.get()); } else return 0; } /** Date_t is milliseconds since epoch */ Date_t jsTime(); /** warning this will wrap */ unsigned curTimeMicros(); unsigned long long curTimeMicros64(); #ifdef _WIN32 // no gettimeofday on windows unsigned long long curTimeMillis64() { boost::xtime xt; boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC); return ((unsigned long long)xt.sec) * 1000 + xt.nsec / 1000000; } Date_t jsTime() { boost::xtime xt; boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC); unsigned long long t = xt.nsec / 1000000; return ((unsigned long long)xt.sec * 1000) + t + getJSTimeVirtualSkew() + getJSTimeVirtualThreadSkew(); } static unsigned long long getFiletime() { FILETIME ft; GetSystemTimeAsFileTime(&ft); return *reinterpret_cast(&ft); } static unsigned long long getPerfCounter() { LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart; } static unsigned long long baseFiletime = 0; static unsigned long long basePerfCounter = 0; static unsigned long long resyncInterval = 0; static boost::mutex _curTimeMicros64ReadMutex; static boost::mutex _curTimeMicros64ResyncMutex; typedef WINBASEAPI VOID(WINAPI* pGetSystemTimePreciseAsFileTime)(_Out_ LPFILETIME lpSystemTimeAsFileTime); static pGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTimeFunc; MONGO_INITIALIZER(Init32TimeSupport)(InitializerContext*) { HINSTANCE kernelLib = LoadLibraryA("kernel32.dll"); if (kernelLib) { GetSystemTimePreciseAsFileTimeFunc = reinterpret_cast( GetProcAddress(kernelLib, "GetSystemTimePreciseAsFileTime")); } return Status::OK(); } static unsigned long long resyncTime() { boost::lock_guard lkResync(_curTimeMicros64ResyncMutex); unsigned long long ftOld; unsigned long long ftNew; ftOld = ftNew = getFiletime(); do { ftNew = getFiletime(); } while (ftOld == ftNew); // wait for filetime to change unsigned long long newPerfCounter = getPerfCounter(); // Make sure that we use consistent values for baseFiletime and basePerfCounter. // boost::lock_guard lkRead(_curTimeMicros64ReadMutex); baseFiletime = ftNew; basePerfCounter = newPerfCounter; resyncInterval = 60 * Timer::getCountsPerSecond(); return newPerfCounter; } unsigned long long curTimeMicros64() { // Windows 8/2012 & later support a <1us time function if (GetSystemTimePreciseAsFileTimeFunc != NULL) { FILETIME time; GetSystemTimePreciseAsFileTimeFunc(&time); return boost::date_time::winapi::file_time_to_microseconds(time); } // Get a current value for QueryPerformanceCounter; if it is not time to resync we will // use this value. // unsigned long long perfCounter = getPerfCounter(); // Periodically resync the timer so that we don't let timer drift accumulate. Testing // suggests that we drift by about one microsecond per minute, so resynching once per // minute should keep drift to no more than one microsecond. // if ((perfCounter - basePerfCounter) > resyncInterval) { perfCounter = resyncTime(); } // Make sure that we use consistent values for baseFiletime and basePerfCounter. // boost::lock_guard lkRead(_curTimeMicros64ReadMutex); // Compute the current time in FILETIME format by adding our base FILETIME and an offset // from that time based on QueryPerformanceCounter. The math is (logically) to compute the // fraction of a second elapsed since 'baseFiletime' by taking the difference in ticks // and dividing by the tick frequency, then scaling this fraction up to units of 100 // nanoseconds to match the FILETIME format. We do the multiplication first to avoid // truncation while using only integer instructions. // unsigned long long computedTime = baseFiletime + ((perfCounter - basePerfCounter) * 10 * 1000 * 1000) / Timer::getCountsPerSecond(); // Convert the computed FILETIME into microseconds since the Unix epoch (1/1/1970). // return boost::date_time::winapi::file_time_to_microseconds(computedTime); } unsigned curTimeMicros() { boost::xtime xt; boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC); unsigned t = xt.nsec / 1000; unsigned secs = xt.sec % 1024; return secs * 1000000 + t; } #else #include unsigned long long curTimeMillis64() { timeval tv; gettimeofday(&tv, NULL); return ((unsigned long long)tv.tv_sec) * 1000 + tv.tv_usec / 1000; } Date_t jsTime() { timeval tv; gettimeofday(&tv, NULL); unsigned long long t = tv.tv_usec / 1000; return ((unsigned long long)tv.tv_sec * 1000) + t + getJSTimeVirtualSkew() + getJSTimeVirtualThreadSkew(); } unsigned long long curTimeMicros64() { timeval tv; gettimeofday(&tv, NULL); return (((unsigned long long)tv.tv_sec) * 1000 * 1000) + tv.tv_usec; } unsigned curTimeMicros() { timeval tv; gettimeofday(&tv, NULL); unsigned secs = tv.tv_sec % 1024; return secs * 1000 * 1000 + tv.tv_usec; } #endif } // namespace mongo MONGO_INITIALIZER_FUNCTION_ASSURE_FILE(util_time_support) mongo-cxx-driver-legacy-1.1.2/src/mongo/util/time_support.h000066400000000000000000000130271273231111400237510ustar00rootroot00000000000000// @file time_support.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include "mongo/base/status_with.h" #include "mongo/client/export_macros.h" namespace mongo { typedef boost::posix_time::milliseconds Milliseconds; typedef boost::posix_time::seconds Seconds; void time_t_to_Struct(time_t t, struct tm* buf, bool local = false); std::string time_t_to_String(time_t t); std::string time_t_to_String_short(time_t t); struct MONGO_CLIENT_API Date_t { // TODO: make signed (and look for related TODO's) unsigned long long millis; Date_t() : millis(0) {} Date_t(unsigned long long m) : millis(m) {} operator unsigned long long&() { return millis; } operator const unsigned long long&() const { return millis; } void toTm(tm* buf); std::string toString() const; time_t toTimeT() const; int64_t asInt64() const { return static_cast(millis); } bool isFormatable() const; }; // uses ISO 8601 dates without trailing Z // colonsOk should be false when creating filenames MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC terseCurrentTime(bool colonsOk = true); /** * Formats "time" according to the ISO 8601 extended form standard, including date, * and time, in the UTC timezone. * * Sample format: "2013-07-23T18:42:14Z" */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC timeToISOString(time_t time); /** * Formats "date" according to the ISO 8601 extended form standard, including date, * and time with milliseconds decimal component, in the UTC timezone. * * Sample format: "2013-07-23T18:42:14.072Z" */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC dateToISOStringUTC(Date_t date); /** * Formats "date" according to the ISO 8601 extended form standard, including date, * and time with milliseconds decimal component, in the local timezone. * * Sample format: "2013-07-23T18:42:14.072-05:00" */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC dateToISOStringLocal(Date_t date); /** * Formats "date" in fixed width in the local time zone. * * Sample format: "Wed Oct 31 13:34:47.996" */ MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC dateToCtimeString(Date_t date); /** * Parses a Date_t from an ISO 8601 string representation. * * Sample formats: "2013-07-23T18:42:14.072-05:00" * "2013-07-23T18:42:14.072Z" * * Local times are currently not supported. */ MONGO_CLIENT_API StatusWith MONGO_CLIENT_FUNC dateFromISOString(const StringData& dateString); /** * Like dateToISOStringUTC, except outputs to a std::ostream. */ MONGO_CLIENT_API void MONGO_CLIENT_FUNC outputDateAsISOStringUTC(std::ostream& os, Date_t date); /** * Like dateToISOStringLocal, except outputs to a std::ostream. */ MONGO_CLIENT_API void MONGO_CLIENT_FUNC outputDateAsISOStringLocal(std::ostream& os, Date_t date); /** * Like dateToCtimeString, except outputs to a std::ostream. */ MONGO_CLIENT_API void MONGO_CLIENT_FUNC outputDateAsCtime(std::ostream& os, Date_t date); boost::gregorian::date currentDate(); // parses time of day in "hh:mm" format assuming 'hh' is 00-23 bool toPointInTime(const std::string& str, boost::posix_time::ptime* timeOfDay); MONGO_CLIENT_API void MONGO_CLIENT_FUNC sleepsecs(int s); MONGO_CLIENT_API void MONGO_CLIENT_FUNC sleepmillis(long long ms); MONGO_CLIENT_API void MONGO_CLIENT_FUNC sleepmicros(long long micros); class Backoff { public: Backoff(int maxSleepMillis, int resetAfter) : _maxSleepMillis(maxSleepMillis), _resetAfterMillis(maxSleepMillis + resetAfter), // Don't reset < the max sleep _lastSleepMillis(0), _lastErrorTimeMillis(0) {} void nextSleepMillis(); /** * testing-only function. used in dbtests/basictests.cpp */ int getNextSleepMillis(int lastSleepMillis, unsigned long long currTimeMillis, unsigned long long lastErrorTimeMillis) const; private: // Parameters int _maxSleepMillis; int _resetAfterMillis; // Last sleep information int _lastSleepMillis; unsigned long long _lastErrorTimeMillis; }; // DO NOT TOUCH except for testing void jsTimeVirtualSkew(long long skew); void jsTimeVirtualThreadSkew(long long skew); long long getJSTimeVirtualThreadSkew(); /** Date_t is milliseconds since epoch */ MONGO_CLIENT_API Date_t MONGO_CLIENT_FUNC jsTime(); /** warning this will wrap */ unsigned curTimeMicros(); unsigned long long curTimeMicros64(); unsigned long long curTimeMillis64(); // these are so that if you use one of them compilation will fail char* asctime(const struct tm* tm); char* ctime(const time_t* timep); struct tm* gmtime(const time_t* timep); struct tm* localtime(const time_t* timep); #if (BOOST_VERSION >= 105000) #define MONGO_BOOST_TIME_UTC boost::TIME_UTC_ #else #define MONGO_BOOST_TIME_UTC boost::TIME_UTC #endif } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/time_support_test.cpp000066400000000000000000001032121273231111400253370ustar00rootroot00000000000000/* Copyright 2013 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault #include #include #include #include "mongo/base/init.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" #include "mongo/util/time_support.h" namespace mongo { namespace { const bool isTimeTSmall = (sizeof(time_t) == sizeof(int32_t)) && std::numeric_limits::is_signed; /** * To make this test deterministic, we set the time zone to America/New_York. */ #ifdef _WIN32 char tzEnvString[] = "TZ=EST+5EDT"; #else char tzEnvString[] = "TZ=America/New_York"; #endif MONGO_INITIALIZER(SetTimeZoneToEasternForTest)(InitializerContext*) { if (-1 == putenv(tzEnvString)) { return Status(ErrorCodes::BadValue, errnoWithDescription()); } tzset(); return Status::OK(); } TEST(TimeFormatting, TimeTAsISO8601Zulu) { ASSERT_EQUALS(std::string("1970-01-01T00:00:00Z"), timeToISOString(0)); ASSERT_EQUALS(std::string("1970-06-30T01:06:40Z"), timeToISOString(15556000)); if (!isTimeTSmall) ASSERT_EQUALS(std::string("2058-02-20T18:29:11Z"), timeToISOString(2781455351LL)); ASSERT_EQUALS(std::string("2013-02-20T18:29:11Z"), timeToISOString(1361384951)); } TEST(TimeFormatting, DateAsISO8601UTCString) { ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"), dateToISOStringUTC(Date_t(0))); ASSERT_EQUALS(std::string("1970-06-30T01:06:40.981Z"), dateToISOStringUTC(Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"), dateToISOStringUTC(Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("2013-02-20T18:29:11.100Z"), dateToISOStringUTC(Date_t(1361384951100ULL))); } TEST(TimeFormatting, DateAsISO8601LocalString) { ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"), dateToISOStringLocal(Date_t(0))); ASSERT_EQUALS(std::string("1970-06-29T21:06:40.981-0400"), dateToISOStringLocal(Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"), dateToISOStringLocal(Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"), dateToISOStringLocal(Date_t(1361384951100ULL))); } TEST(TimeFormatting, DateAsCtimeString) { ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"), dateToCtimeString(Date_t(0))); ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"), dateToCtimeString(Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"), dateToCtimeString(Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"), dateToCtimeString(Date_t(1361384951100ULL))); } static std::string stringstreamDate(void (*formatter)(std::ostream&, Date_t), Date_t date) { std::ostringstream os; formatter(os, date); return os.str(); } TEST(TimeFormatting, DateAsISO8601UTCStream) { ASSERT_EQUALS(std::string("1970-01-01T00:00:00.000Z"), stringstreamDate(outputDateAsISOStringUTC, Date_t(0))); ASSERT_EQUALS(std::string("1970-06-30T01:06:40.981Z"), stringstreamDate(outputDateAsISOStringUTC, Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("2058-02-20T18:29:11.100Z"), stringstreamDate(outputDateAsISOStringUTC, Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("2013-02-20T18:29:11.100Z"), stringstreamDate(outputDateAsISOStringUTC, Date_t(1361384951100ULL))); } TEST(TimeFormatting, DateAsISO8601LocalStream) { ASSERT_EQUALS(std::string("1969-12-31T19:00:00.000-0500"), stringstreamDate(outputDateAsISOStringLocal, Date_t(0))); ASSERT_EQUALS(std::string("1970-06-29T21:06:40.981-0400"), stringstreamDate(outputDateAsISOStringLocal, Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("2058-02-20T13:29:11.100-0500"), stringstreamDate(outputDateAsISOStringLocal, Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("2013-02-20T13:29:11.100-0500"), stringstreamDate(outputDateAsISOStringLocal, Date_t(1361384951100ULL))); } TEST(TimeFormatting, DateAsCtimeStream) { ASSERT_EQUALS(std::string("Wed Dec 31 19:00:00.000"), stringstreamDate(outputDateAsCtime, Date_t(0))); ASSERT_EQUALS(std::string("Mon Jun 29 21:06:40.981"), stringstreamDate(outputDateAsCtime, Date_t(15556000981ULL))); if (!isTimeTSmall) ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"), stringstreamDate(outputDateAsCtime, Date_t(2781455351100ULL))); ASSERT_EQUALS(std::string("Wed Feb 20 13:29:11.100"), stringstreamDate(outputDateAsCtime, Date_t(1361384951100ULL))); } TEST(TimeParsing, DateAsISO8601UTC) { // Allowed date format: // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]Z // Year, month, day, hour, and minute are required, while the seconds component and one to // three milliseconds are optional. StatusWith swull = dateFromISOString("1971-02-03T04:05:06.789Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906789ULL); swull = dateFromISOString("1971-02-03T04:05:06.78Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906780ULL); swull = dateFromISOString("1971-02-03T04:05:06.7Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906700ULL); swull = dateFromISOString("1971-02-03T04:05:06Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906000ULL); swull = dateFromISOString("1971-02-03T04:05Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401900000ULL); swull = dateFromISOString("1970-01-01T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 0ULL); swull = dateFromISOString("1970-06-30T01:06:40.981Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 15556000981ULL); if (!isTimeTSmall) { swull = dateFromISOString("2058-02-20T18:29:11.100Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2781455351100ULL); swull = dateFromISOString("3001-01-01T08:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 32535244800000ULL); } swull = dateFromISOString("2013-02-20T18:29:11.100Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1361384951100ULL); } TEST(TimeParsing, DateAsISO8601Local) { // Allowed date format: // YYYY-MM-DDTHH:MM[:SS[.m[m[m]]]]+HHMM // Year, month, day, hour, and minute are required, while the seconds component and one to // three milliseconds are optional. The time zone offset must be four digits. StatusWith swull = dateFromISOString("1971-02-03T09:16:06.789+0511"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906789ULL); swull = dateFromISOString("1971-02-03T09:16:06.78+0511"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906780ULL); swull = dateFromISOString("1971-02-03T09:16:06.7+0511"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906700ULL); swull = dateFromISOString("1971-02-03T09:16:06+0511"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401906000ULL); swull = dateFromISOString("1971-02-03T09:16+0511"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 34401900000ULL); swull = dateFromISOString("1970-01-01T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 0ULL); swull = dateFromISOString("1970-06-30T01:06:40.981Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 15556000981ULL); // Local times not supported // swull = dateFromISOString("1970-01-01T00:00:00.001"); // ASSERT_OK(swull.getStatus()); // ASSERT_EQUALS(swull.getValue(), 18000001ULL); // swull = dateFromISOString("1970-01-01T00:00:00.01"); // ASSERT_OK(swull.getStatus()); // ASSERT_EQUALS(swull.getValue(), 18000010ULL); // swull = dateFromISOString("1970-01-01T00:00:00.1"); // ASSERT_OK(swull.getStatus()); // ASSERT_EQUALS(swull.getValue(), 18000100ULL); // swull = dateFromISOString("1970-01-01T00:00:01"); // ASSERT_OK(swull.getStatus()); // ASSERT_EQUALS(swull.getValue(), 18001000ULL); // swull = dateFromISOString("1970-01-01T00:01"); // ASSERT_OK(swull.getStatus()); // ASSERT_EQUALS(swull.getValue(), 18060000ULL); swull = dateFromISOString("1970-06-29T21:06:40.981-0400"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 15556000981ULL); if (!isTimeTSmall) { swull = dateFromISOString("2058-02-20T13:29:11.100-0500"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2781455351100ULL); swull = dateFromISOString("3000-12-31T23:59:59Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 32535215999000ULL); } else { swull = dateFromISOString("2038-01-19T03:14:07Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2147483647000ULL); } swull = dateFromISOString("2013-02-20T13:29:11.100-0500"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1361384951100ULL); swull = dateFromISOString("2013-02-20T13:29:11.100-0501"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1361385011100ULL); } TEST(TimeParsing, InvalidDates) { // Invalid decimal ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0.0Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.0.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:.0:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T.0:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-.1T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-.1-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString(".970-01-01T00:00:00.000Z").getStatus()); // Extra sign characters ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.+00Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:+0.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:+0:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T+0:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-+1T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-+1-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("+970-01-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.-00Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:-0.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:-0:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T-0:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01--1T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970--1-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("-970-01-01T00:00:00.000Z").getStatus()); // Out of range ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:60.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:60:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T24:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-32T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-00T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-13-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-00-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1969-01-01T00:00:00.000Z").getStatus()); // Invalid lengths ASSERT_NOT_OK(dateFromISOString("01970-01-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-001-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-001T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T000:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:000:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:000.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.0000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("197-01-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-1-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-1T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T0:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:0:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:0.000Z").getStatus()); // Invalid delimiters ASSERT_NOT_OK(dateFromISOString("1970+01-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01+01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01Q00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00-00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00-00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00-000Z").getStatus()); // Missing numbers ASSERT_NOT_OK(dateFromISOString("1970--01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00::00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.Z").getStatus()); // Bad time offset field ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01ZZ").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01-11111").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01Z1111").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+111").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+1160").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+2400").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01+00+0").getStatus()); // Bad prefixes ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:01.").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:00:").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05:").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T05+0500").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01+0500").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01+0500").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970+0500").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T01Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970Z").getStatus()); // No local time ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.000").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970").getStatus()); // Invalid hex base specifiers ASSERT_NOT_OK(dateFromISOString("x970-01-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-x1-01T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-x1T00:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01Tx0:00:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:x0:00.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:x0.000Z").getStatus()); ASSERT_NOT_OK(dateFromISOString("1970-01-01T00:00:00.x00Z").getStatus()); } TEST(TimeParsing, LeapYears) { StatusWith swull = dateFromISOString("1972-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 68169600000ULL); swull = dateFromISOString("1976-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 194400000000ULL); swull = dateFromISOString("1980-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 320630400000ULL); swull = dateFromISOString("1984-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 446860800000ULL); swull = dateFromISOString("1988-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 573091200000ULL); swull = dateFromISOString("1992-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 699321600000ULL); swull = dateFromISOString("1996-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 825552000000ULL); swull = dateFromISOString("2000-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 951782400000ULL); swull = dateFromISOString("2004-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1078012800000ULL); swull = dateFromISOString("2008-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1204243200000ULL); swull = dateFromISOString("2012-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1330473600000ULL); swull = dateFromISOString("2016-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1456704000000ULL); swull = dateFromISOString("2020-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1582934400000ULL); swull = dateFromISOString("2024-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1709164800000ULL); swull = dateFromISOString("2028-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1835395200000ULL); swull = dateFromISOString("2032-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 1961625600000ULL); swull = dateFromISOString("2036-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2087856000000ULL); if (!isTimeTSmall) { swull = dateFromISOString("2040-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2214086400000ULL); swull = dateFromISOString("2044-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2340316800000ULL); swull = dateFromISOString("2048-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2466547200000ULL); swull = dateFromISOString("2052-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2592777600000ULL); swull = dateFromISOString("2056-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2719008000000ULL); swull = dateFromISOString("2060-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2845238400000ULL); swull = dateFromISOString("2064-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 2971468800000ULL); swull = dateFromISOString("2068-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3097699200000ULL); swull = dateFromISOString("2072-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3223929600000ULL); swull = dateFromISOString("2076-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3350160000000ULL); swull = dateFromISOString("2080-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3476390400000ULL); swull = dateFromISOString("2084-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3602620800000ULL); swull = dateFromISOString("2088-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3728851200000ULL); swull = dateFromISOString("2092-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3855081600000ULL); swull = dateFromISOString("2096-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 3981312000000ULL); swull = dateFromISOString("2104-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4233686400000ULL); swull = dateFromISOString("2108-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4359916800000ULL); swull = dateFromISOString("2112-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4486147200000ULL); swull = dateFromISOString("2116-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4612377600000ULL); swull = dateFromISOString("2120-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4738608000000ULL); swull = dateFromISOString("2124-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4864838400000ULL); swull = dateFromISOString("2128-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 4991068800000ULL); swull = dateFromISOString("2132-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5117299200000ULL); swull = dateFromISOString("2136-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5243529600000ULL); swull = dateFromISOString("2140-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5369760000000ULL); swull = dateFromISOString("2144-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5495990400000ULL); swull = dateFromISOString("2148-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5622220800000ULL); swull = dateFromISOString("2152-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5748451200000ULL); swull = dateFromISOString("2156-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 5874681600000ULL); swull = dateFromISOString("2160-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6000912000000ULL); swull = dateFromISOString("2164-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6127142400000ULL); swull = dateFromISOString("2168-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6253372800000ULL); swull = dateFromISOString("2172-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6379603200000ULL); swull = dateFromISOString("2176-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6505833600000ULL); swull = dateFromISOString("2180-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6632064000000ULL); swull = dateFromISOString("2184-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6758294400000ULL); swull = dateFromISOString("2188-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 6884524800000ULL); swull = dateFromISOString("2192-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7010755200000ULL); swull = dateFromISOString("2196-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7136985600000ULL); swull = dateFromISOString("2204-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7389360000000ULL); swull = dateFromISOString("2208-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7515590400000ULL); swull = dateFromISOString("2212-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7641820800000ULL); swull = dateFromISOString("2216-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7768051200000ULL); swull = dateFromISOString("2220-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 7894281600000ULL); swull = dateFromISOString("2224-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8020512000000ULL); swull = dateFromISOString("2228-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8146742400000ULL); swull = dateFromISOString("2232-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8272972800000ULL); swull = dateFromISOString("2236-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8399203200000ULL); swull = dateFromISOString("2240-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8525433600000ULL); swull = dateFromISOString("2244-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8651664000000ULL); swull = dateFromISOString("2248-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8777894400000ULL); swull = dateFromISOString("2252-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 8904124800000ULL); swull = dateFromISOString("2256-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9030355200000ULL); swull = dateFromISOString("2260-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9156585600000ULL); swull = dateFromISOString("2264-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9282816000000ULL); swull = dateFromISOString("2268-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9409046400000ULL); swull = dateFromISOString("2272-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9535276800000ULL); swull = dateFromISOString("2276-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9661507200000ULL); swull = dateFromISOString("2280-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9787737600000ULL); swull = dateFromISOString("2284-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 9913968000000ULL); swull = dateFromISOString("2288-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10040198400000ULL); swull = dateFromISOString("2292-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10166428800000ULL); swull = dateFromISOString("2296-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10292659200000ULL); swull = dateFromISOString("2304-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10545033600000ULL); swull = dateFromISOString("2308-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10671264000000ULL); swull = dateFromISOString("2312-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10797494400000ULL); swull = dateFromISOString("2316-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 10923724800000ULL); swull = dateFromISOString("2320-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11049955200000ULL); swull = dateFromISOString("2324-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11176185600000ULL); swull = dateFromISOString("2328-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11302416000000ULL); swull = dateFromISOString("2332-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11428646400000ULL); swull = dateFromISOString("2336-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11554876800000ULL); swull = dateFromISOString("2340-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11681107200000ULL); swull = dateFromISOString("2344-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11807337600000ULL); swull = dateFromISOString("2348-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 11933568000000ULL); swull = dateFromISOString("2352-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12059798400000ULL); swull = dateFromISOString("2356-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12186028800000ULL); swull = dateFromISOString("2360-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12312259200000ULL); swull = dateFromISOString("2364-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12438489600000ULL); swull = dateFromISOString("2368-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12564720000000ULL); swull = dateFromISOString("2372-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12690950400000ULL); swull = dateFromISOString("2376-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12817180800000ULL); swull = dateFromISOString("2380-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 12943411200000ULL); swull = dateFromISOString("2384-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 13069641600000ULL); swull = dateFromISOString("2388-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 13195872000000ULL); swull = dateFromISOString("2392-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 13322102400000ULL); swull = dateFromISOString("2396-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 13448332800000ULL); swull = dateFromISOString("2400-02-29T00:00:00.000Z"); ASSERT_OK(swull.getStatus()); ASSERT_EQUALS(swull.getValue(), 13574563200000ULL); } } } // namespace } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer-generic-inl.h000066400000000000000000000022541273231111400245310ustar00rootroot00000000000000// @file mongo/util/timer-generic-inl.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Inline function implementations for the "generic" implementation of the * Timer class. This implementation often has pretty poor resolution, but is available * on all supported platforms. * * This file should only be included through timer-inl.h, which selects the * particular implementation based on target platform. */ #pragma once #define MONGO_TIMER_IMPL_GENERIC #include "mongo/util/time_support.h" namespace mongo { unsigned long long Timer::now() const { return curTimeMicros64(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer-inl.h000066400000000000000000000031221273231111400231120ustar00rootroot00000000000000// @file mongo/util/timer-inl.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Inline function implementations for the Timer class. This file simply selects * the platform-appropriate inline functions to include. * * This file should only be included through timer-inl.h, which selects the * particular implementation based on target platform. */ #pragma once #include "mongo/config.h" #if defined(MONGO_HAVE_HEADER_UNISTD_H) #include #endif #if defined(_WIN32) // On Windows, prefer the Windows-specific implementation, which employs QueryPerformanceCounter. #include "mongo/util/timer-win32-inl.h" #elif defined(_POSIX_TIMERS) and _POSIX_TIMERS > 0 and defined(_POSIX_MONOTONIC_CLOCK) and \ _POSIX_MONOTONIC_CLOCK > 0 // On systems that support the POSIX clock_gettime function, and the "monotonic" clock, // use those. #include "mongo/util/timer-posixclock-inl.h" #else // If all else fails, fall back to a generic implementation. Performance may suffer. #include "mongo/util/timer-generic-inl.h" #endif mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer-posixclock-inl.h000066400000000000000000000027611273231111400252760ustar00rootroot00000000000000/* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Inline function implementations for timers on systems that support the * POSIX clock API and CLOCK_MONOTONIC clock. * * This file should only be included through timer-inl.h, which selects the * particular implementation based on target platform. */ #define MONGO_TIMER_IMPL_POSIX_MONOTONIC_CLOCK #include #include "mongo/util/assert_util.h" namespace mongo { unsigned long long Timer::now() const { timespec the_time; unsigned long long result; fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time)); // Safe for 292 years after the clock epoch, even if we switch to a signed time value. On // Linux, the monotonic clock's epoch is the UNIX epoch. result = static_cast(the_time.tv_sec); result *= nanosPerSecond; result += static_cast(the_time.tv_nsec); return result; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer-win32-inl.h000066400000000000000000000025171273231111400240610ustar00rootroot00000000000000// @file mongo/util/timer-win32-inl.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Inline function implementations for the Windows-specific implementation of the * Timer class. Windows selects the best available timer, in its estimation, for * measuring time at high resolution. This may be the HPET of the TSC on x86 systems, * but is promised to be synchronized across processors, barring BIOS errors. * * Do not include directly. Include "mongo/util/timer.h". */ #pragma once #define MONGO_TIMER_IMPL_WIN32 #include "mongo/platform/windows_basic.h" #include "mongo/util/assert_util.h" namespace mongo { unsigned long long Timer::now() const { LARGE_INTEGER i; fassert(16161, QueryPerformanceCounter(&i)); return i.QuadPart; } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer.cpp000066400000000000000000000074141273231111400226750ustar00rootroot00000000000000// @file mongo/util/timer.cpp /* Copyright 2009 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/platform/basic.h" #include "mongo/util/timer.h" #include #include #if defined(MONGO_HAVE_HEADER_UNISTD_H) #include #endif #include "mongo/util/assert_util.h" #include "mongo/util/time_support.h" namespace mongo { // Set default value to reflect "generic" timer implementation. // Define Timer::_countsPerSecond before static initializer "atstartuputil" to ensure correct // relative sequencing regardless of how _countsPerSecond is initialized (static or dynamic). long long Timer::_countsPerSecond = Timer::microsPerSecond; double Timer::_microsPerCount = 1.0f; namespace { // TODO: SERVER-5112, better startup-time initialization of C++ modules. struct AtStartup { AtStartup(); } atstartuputil; // "Generic" implementation for Timer::now(). long long _timerNowGeneric() { return curTimeMicros64(); } // Function pointer to Timer::now() implementation. // Overridden in AtStartup() with better implementation where available. long long (*_timerNow)() = &_timerNowGeneric; #if defined(_WIN32) /** * Windows-specific implementation of the * Timer class. Windows selects the best available timer, in its estimation, for * measuring time at high resolution. This may be the HPET of the TSC on x86 systems, * but is promised to be synchronized across processors, barring BIOS errors. */ long long timerNowWindows() { LARGE_INTEGER i; fassert(16161, QueryPerformanceCounter(&i)); return i.QuadPart; } AtStartup::AtStartup() { LARGE_INTEGER x; bool ok = QueryPerformanceFrequency(&x); verify(ok); Timer::setCountsPerSecond(x.QuadPart); _timerNow = &timerNowWindows; } #elif defined(MONGO_HAVE_POSIX_MONOTONIC_CLOCK) /** * Implementation for timer on systems that support the * POSIX clock API and CLOCK_MONOTONIC clock. */ long long timerNowPosixMonotonicClock() { timespec the_time; long long result; fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time)); // Safe for 292 years after the clock epoch, even if we switch to a signed time value. // On Linux, the monotonic clock's epoch is the UNIX epoch. result = static_cast(the_time.tv_sec); result *= Timer::nanosPerSecond; result += static_cast(the_time.tv_nsec); return result; } AtStartup::AtStartup() { // If the monotonic clock is not available at runtime (sysconf() returns 0 or -1), // do not override the generic implementation or modify Timer::_countsPerSecond. if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) { return; } Timer::setCountsPerSecond(Timer::nanosPerSecond); _timerNow = &timerNowPosixMonotonicClock; // Make sure that the current time relative to the (unspecified) epoch isn't already too // big to represent as a 64-bit count of nanoseconds. long long maxSecs = std::numeric_limits::max() / Timer::nanosPerSecond; timespec the_time; fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time)); fassert(16163, static_cast(the_time.tv_sec) < maxSecs); } #else AtStartup::AtStartup() {} #endif } // namespace long long Timer::now() const { return _timerNow(); } } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/timer.h000066400000000000000000000061641273231111400223430ustar00rootroot00000000000000// @file timer.h /* Copyright 2010 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "mongo/client/export_macros.h" namespace mongo { /** * Time tracking object. * * Should be of reasonably high performance, though the implementations are platform-specific. * Each platform provides a distinct implementation of the now() method, and sets the * _countsPerSecond static field to the constant number of ticks per second that now() counts * in. The maximum span measurable by the counter and convertible to microseconds is about 10 * trillion ticks. As long as there are fewer than 100 ticks per nanosecond, timer durations of * 2.5 years will be supported. Since a typical tick duration will be under 10 per nanosecond, * if not below 1 per nanosecond, this should not be an issue. */ class Timer /*copyable*/ { public: static const long long millisPerSecond = 1000; static const long long microsPerSecond = 1000 * millisPerSecond; static const long long nanosPerSecond = 1000 * microsPerSecond; Timer() { reset(); } int seconds() const { return (int)(micros() / 1000000); } int millis() const { return (int)(micros() / 1000); } int minutes() const { return seconds() / 60; } /** Get the time interval and reset at the same time. * @return time in milliseconds. */ inline int millisReset() { const long long nextNow = now(); const long long deltaMicros = static_cast((nextNow - _old) * _microsPerCount); _old = nextNow; return static_cast(deltaMicros / 1000); } inline long long micros() const { return static_cast((now() - _old) * _microsPerCount); } inline void reset() { _old = now(); } inline static void setCountsPerSecond(long long countsPerSecond) { _countsPerSecond = countsPerSecond; _microsPerCount = static_cast(microsPerSecond) / _countsPerSecond; } inline static long long getCountsPerSecond() { return _countsPerSecond; } private: /** * Internally, the timer counts platform-dependent ticks of some sort, and * must then convert those ticks to microseconds and their ilk. This field * stores the frequency of the platform-dependent counter. */ static long long _countsPerSecond; // Derived value from _countsPerSecond. This represents the conversion ratio // from clock ticks to microseconds. static double _microsPerCount; long long now() const; long long _old; }; } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/mongo/util/unordered_fast_key_table.h000066400000000000000000000137031273231111400262430ustar00rootroot00000000000000// unordered_fast_key_table.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "mongo/base/disallow_copying.h" namespace mongo { template struct UnorderedFastKeyTable_LS_C { K_S operator()(const K_L& a) const { return K_S(a); } }; template K_L typename C_LS = UnorderedFastKeyTable_LS_C // convertor from K_L -> K_S > class UnorderedFastKeyTable { public: typedef std::pair value_type; typedef K_L key_type; typedef V mapped_type; private: struct Entry { Entry() : used(false), everUsed(false) {} bool used; bool everUsed; size_t curHash; value_type data; }; struct Area { Area(unsigned capacity, double maxProbeRatio); Area(const Area& other); int find(const K_L& key, size_t hash, int* firstEmpty, const UnorderedFastKeyTable& sm) const; bool transfer(Area* newArea, const UnorderedFastKeyTable& sm) const; void swap(Area* other) { using std::swap; swap(_capacity, other->_capacity); swap(_maxProbe, other->_maxProbe); swap(_entries, other->_entries); } unsigned _capacity; unsigned _maxProbe; boost::scoped_array _entries; }; public: static const unsigned DEFAULT_STARTING_CAPACITY = 20; /** * @param startingCapacity how many buckets should exist on initial creation * DEFAULT_STARTING_CAPACITY * @param maxProbeRatio the percentage of buckets we're willing to probe * no defined default as you can't have a static const double on windows */ UnorderedFastKeyTable(unsigned startingCapacity = DEFAULT_STARTING_CAPACITY, double maxProbeRatio = 0.05); UnorderedFastKeyTable(const UnorderedFastKeyTable& other); UnorderedFastKeyTable& operator=(const UnorderedFastKeyTable& other) { other.copyTo(this); return *this; } void copyTo(UnorderedFastKeyTable* out) const; /** * @return number of elements in map */ size_t size() const { return _size; } bool empty() const { return _size == 0; } /* * @return storage space */ size_t capacity() const { return _area._capacity; } V& operator[](const K_L& key) { return get(key); } V& get(const K_L& key); /** * @return number of elements removed */ size_t erase(const K_L& key); class const_iterator { friend class UnorderedFastKeyTable; public: const_iterator() { _position = -1; } const_iterator(const Area* area) { _area = area; _position = 0; _max = _area->_capacity - 1; _skip(); } const_iterator(const Area* area, int pos) { _area = area; _position = pos; _max = pos; } const value_type* operator->() const { return &_area->_entries[_position].data; } const value_type& operator*() const { return _area->_entries[_position].data; } const_iterator operator++() { if (_position < 0) return *this; _position++; if (_position > _max) _position = -1; else _skip(); return *this; } bool operator==(const const_iterator& other) const { return _position == other._position; } bool operator!=(const const_iterator& other) const { return _position != other._position; } private: void _skip() { while (true) { if (_area->_entries[_position].used) break; if (_position >= _max) { _position = -1; break; } ++_position; } } const Area* _area; int _position; int _max; // inclusive }; void erase(const_iterator it); /** * @return either a one-shot iterator with the key, or end() */ const_iterator find(const K_L& key) const; const_iterator begin() const; const_iterator end() const; private: /* * @param firstEmpty, if we return -1, and firstEmpty != NULL, * this will be set to the first empty bucket we found * @retrun offset into _entries or -1 if not there */ int _find(const K_L& key, int hash, int* firstEmpty) const; void _grow(); // ---- size_t _size; double _maxProbeRatio; Area _area; H _hash; E _equals; C _convertor; C_LS _convertorOther; }; } #include "mongo/util/unordered_fast_key_table_internal.h" mongo-cxx-driver-legacy-1.1.2/src/mongo/util/unordered_fast_key_table_internal.h000066400000000000000000000172421273231111400301410ustar00rootroot00000000000000// unordered_fast_key_table_internal.h /* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mongo/util/assert_util.h" #include "mongo/util/debug_util.h" namespace mongo { template inline UnorderedFastKeyTable::Area::Area(unsigned capacity, double maxProbeRatio) : _capacity(capacity), _maxProbe(static_cast(capacity * maxProbeRatio)), _entries(new Entry[_capacity]) {} template inline UnorderedFastKeyTable::Area::Area(const Area& other) : _capacity(other._capacity), _maxProbe(other._maxProbe), _entries(new Entry[_capacity]) { for (unsigned i = 0; i < _capacity; i++) { _entries[i] = other._entries[i]; } } template inline int UnorderedFastKeyTable::Area::find( const K_L& key, size_t hash, int* firstEmpty, const UnorderedFastKeyTable& sm) const { if (firstEmpty) *firstEmpty = -1; for (unsigned probe = 0; probe < _maxProbe; probe++) { unsigned pos = (hash + probe) % _capacity; if (!_entries[pos].used) { // space is empty if (firstEmpty && *firstEmpty == -1) *firstEmpty = pos; if (!_entries[pos].everUsed) return -1; continue; } if (_entries[pos].curHash != hash) { // space has something else continue; } if (!sm._equals(key, sm._convertor(_entries[pos].data.first))) { // hashes match // strings are not equals continue; } // hashes and strings are equal // yay! return pos; } return -1; } template inline bool UnorderedFastKeyTable::Area::transfer( Area* newArea, const UnorderedFastKeyTable& sm) const { for (unsigned i = 0; i < _capacity; i++) { if (!_entries[i].used) continue; int firstEmpty = -1; int loc = newArea->find( sm._convertor(_entries[i].data.first), _entries[i].curHash, &firstEmpty, sm); verify(loc == -1); if (firstEmpty < 0) { return false; } newArea->_entries[firstEmpty] = _entries[i]; } return true; } template inline UnorderedFastKeyTable::UnorderedFastKeyTable( unsigned startingCapacity, double maxProbeRatio) : _maxProbeRatio(maxProbeRatio), _area(startingCapacity, maxProbeRatio) { _size = 0; } template inline UnorderedFastKeyTable::UnorderedFastKeyTable( const UnorderedFastKeyTable& other) : _size(other._size), _maxProbeRatio(other._maxProbeRatio), _area(other._area), _hash(other._hash), _equals(other._equals), _convertor(other._convertor), _convertorOther(other._convertorOther) {} template inline void UnorderedFastKeyTable::copyTo( UnorderedFastKeyTable* out) const { out->_size = _size; out->_maxProbeRatio = _maxProbeRatio; Area x(_area); out->_area.swap(&x); } template inline V& UnorderedFastKeyTable::get(const K_L& key) { const size_t hash = _hash(key); for (int numGrowTries = 0; numGrowTries < 5; numGrowTries++) { int firstEmpty = -1; int pos = _area.find(key, hash, &firstEmpty, *this); if (pos >= 0) return _area._entries[pos].data.second; // key not in map // need to add if (firstEmpty >= 0) { _size++; _area._entries[firstEmpty].used = true; _area._entries[firstEmpty].everUsed = true; _area._entries[firstEmpty].curHash = hash; _area._entries[firstEmpty].data.first = _convertorOther(key); return _area._entries[firstEmpty].data.second; } // no space left in map _grow(); } msgasserted(16471, "UnorderedFastKeyTable couldn't add entry after growing many times"); } template inline size_t UnorderedFastKeyTable::erase(const K_L& key) { const size_t hash = _hash(key); int pos = _area.find(key, hash, NULL, *this); if (pos < 0) return 0; --_size; _area._entries[pos].used = false; _area._entries[pos].data.second = V(); return 1; } template void UnorderedFastKeyTable::erase(const_iterator it) { dassert(it._position >= 0); dassert(it._area == &_area); --_size; _area._entries[it._position].used = false; _area._entries[it._position].data.second = V(); } template inline void UnorderedFastKeyTable::_grow() { unsigned capacity = _area._capacity; for (int numGrowTries = 0; numGrowTries < 5; numGrowTries++) { capacity *= 2; Area newArea(capacity, _maxProbeRatio); bool success = _area.transfer(&newArea, *this); if (!success) { continue; } _area.swap(&newArea); return; } msgasserted(16845, "UnorderedFastKeyTable::_grow couldn't add entry after growing many times"); } template inline typename UnorderedFastKeyTable::const_iterator UnorderedFastKeyTable::find(const K_L& key) const { if (_size == 0) return const_iterator(); int pos = _area.find(key, _hash(key), 0, *this); if (pos < 0) return const_iterator(); return const_iterator(&_area, pos); } template inline typename UnorderedFastKeyTable::const_iterator UnorderedFastKeyTable::end() const { return const_iterator(); } template inline typename UnorderedFastKeyTable::const_iterator UnorderedFastKeyTable::begin() const { return const_iterator(&_area); } } mongo-cxx-driver-legacy-1.1.2/src/mongo/version.h.in000066400000000000000000000033611273231111400223340ustar00rootroot00000000000000/* Copyright 2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #define MONGOCLIENT_VERSION_MAJOR @mongoclient_version_major@ #define MONGOCLIENT_VERSION_MINOR @mongoclient_version_minor@ #define MONGOCLIENT_VERSION_PATCH @mongoclient_version_patch@ #define MONGOCLIENT_VERSION \ ((MONGOCLIENT_VERSION_MAJOR * 10000) + \ (MONGOCLIENT_VERSION_MINOR * 100) + \ MONGOCLIENT_VERSION_PATCH) \ namespace mongo { namespace client { const unsigned int kVersionMajor = MONGOCLIENT_VERSION_MAJOR; const unsigned int kVersionMinor = MONGOCLIENT_VERSION_MINOR; const unsigned int kVersionPatch = MONGOCLIENT_VERSION_PATCH; const unsigned int kVersion = MONGOCLIENT_VERSION; // The string version of the library. // TOOD: should the value of this be here, or buried in a .cpp file as an extern? const char kVersionString[] = "@mongoclient_version@"; // The stringified SHA1 of the revision from which this binary was built. // TODO: should the value of this be here, or buried on a .cpp file as an extern? const char kGitRevision[] = "@mongoclient_git_revision@"; } // namespace client } // namespace mongo mongo-cxx-driver-legacy-1.1.2/src/third_party/000077500000000000000000000000001273231111400213005ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/SConscript000066400000000000000000000001171273231111400233110ustar00rootroot00000000000000# -*- mode: python -*- Import("env") env.SConscript('gtest-1.7.0/SConscript') mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/000077500000000000000000000000001273231111400230675ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/CHANGES000066400000000000000000000147651273231111400240770ustar00rootroot00000000000000Changes for 1.7.0: * New feature: death tests are supported on OpenBSD and in iOS simulator now. * New feature: Google Test now implements a protocol to allow a test runner to detect that a test program has exited prematurely and report it as a failure (before it would be falsely reported as a success if the exit code is 0). * New feature: Test::RecordProperty() can now be used outside of the lifespan of a test method, in which case it will be attributed to the current test case or the test program in the XML report. * New feature (potentially breaking): --gtest_list_tests now prints the type parameters and value parameters for each test. * Improvement: char pointers and char arrays are now escaped properly in failure messages. * Improvement: failure summary in XML reports now includes file and line information. * Improvement: the XML element now has a timestamp attribute. * Improvement: When --gtest_filter is specified, XML report now doesn't contain information about tests that are filtered out. * Fixed the bug where long --gtest_filter flag values are truncated in death tests. * Potentially breaking change: RUN_ALL_TESTS() is now implemented as a function instead of a macro in order to work better with Clang. * Compatibility fixes with C++ 11 and various platforms. * Bug/warning fixes. Changes for 1.6.0: * New feature: ADD_FAILURE_AT() for reporting a test failure at the given source location -- useful for writing testing utilities. * New feature: the universal value printer is moved from Google Mock to Google Test. * New feature: type parameters and value parameters are reported in the XML report now. * A gtest_disable_pthreads CMake option. * Colored output works in GNU Screen sessions now. * Parameters of value-parameterized tests are now printed in the textual output. * Failures from ad hoc test assertions run before RUN_ALL_TESTS() are now correctly reported. * Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to ostream. * More complete handling of exceptions. * GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter name is already used by another library. * --gtest_catch_exceptions is now true by default, allowing a test program to continue after an exception is thrown. * Value-parameterized test fixtures can now derive from Test and WithParamInterface separately, easing conversion of legacy tests. * Death test messages are clearly marked to make them more distinguishable from other messages. * Compatibility fixes for Android, Google Native Client, MinGW, HP UX, PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear), IBM XL C++ (Visual Age C++), and C++0x. * Bug fixes and implementation clean-ups. * Potentially incompatible changes: disables the harmful 'make install' command in autotools. Changes for 1.5.0: * New feature: assertions can be safely called in multiple threads where the pthreads library is available. * New feature: predicates used inside EXPECT_TRUE() and friends can now generate custom failure messages. * New feature: Google Test can now be compiled as a DLL. * New feature: fused source files are included. * New feature: prints help when encountering unrecognized Google Test flags. * Experimental feature: CMake build script (requires CMake 2.6.4+). * Experimental feature: the Pump script for meta programming. * double values streamed to an assertion are printed with enough precision to differentiate any two different values. * Google Test now works on Solaris and AIX. * Build and test script improvements. * Bug fixes and implementation clean-ups. Potentially breaking changes: * Stopped supporting VC++ 7.1 with exceptions disabled. * Dropped support for 'make install'. Changes for 1.4.0: * New feature: the event listener API * New feature: test shuffling * New feature: the XML report format is closer to junitreport and can be parsed by Hudson now. * New feature: when a test runs under Visual Studio, its failures are integrated in the IDE. * New feature: /MD(d) versions of VC++ projects. * New feature: elapsed time for the tests is printed by default. * New feature: comes with a TR1 tuple implementation such that Boost is no longer needed for Combine(). * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends. * New feature: the Xcode project can now produce static gtest libraries in addition to a framework. * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile, Symbian, gcc, and C++Builder. * Bug fixes and implementation clean-ups. Changes for 1.3.0: * New feature: death tests on Windows, Cygwin, and Mac. * New feature: ability to use Google Test assertions in other testing frameworks. * New feature: ability to run disabled test via --gtest_also_run_disabled_tests. * New feature: the --help flag for printing the usage. * New feature: access to Google Test flag values in user code. * New feature: a script that packs Google Test into one .h and one .cc file for easy deployment. * New feature: support for distributing test functions to multiple machines (requires support from the test runner). * Bug fixes and implementation clean-ups. Changes for 1.2.1: * Compatibility fixes for Linux IA-64 and IBM z/OS. * Added support for using Boost and other TR1 implementations. * Changes to the build scripts to support upcoming release of Google C++ Mocking Framework. * Added Makefile to the distribution package. * Improved build instructions in README. Changes for 1.2.0: * New feature: value-parameterized tests. * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS) macros. * Changed the XML report format to match JUnit/Ant's. * Added tests to the Xcode project. * Added scons/SConscript for building with SCons. * Added src/gtest-all.cc for building Google Test from a single file. * Fixed compatibility with Solaris and z/OS. * Enabled running Python tests on systems with python 2.3 installed, e.g. Mac OS X 10.4. * Bug fixes. Changes for 1.1.0: * New feature: type-parameterized tests. * New feature: exception assertions. * New feature: printing elapsed time of tests. * Improved the robustness of death tests. * Added an Xcode project and samples. * Adjusted the output format on Windows to be understandable by Visual Studio. * Minor bug fixes. Changes for 1.0.1: * Added project files for Visual Studio 7.1. * Fixed issues with compiling on Mac OS X. * Fixed issues with compiling on Cygwin. Changes for 1.0.0: * Initial Open Source release of Google Test mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/CMakeLists.txt000066400000000000000000000216401273231111400256320ustar00rootroot00000000000000######################################################################## # CMake build script for Google Test. # # To run the tests for Google Test itself on Linux, use 'make test' or # ctest. You can select which tests to run using 'ctest -R regex'. # For more options, run 'ctest --help'. # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) # When other libraries are using a shared version of runtime libraries, # Google Test also has to use one. option( gtest_force_shared_crt "Use shared (DLL) run-time lib even when Google Test is built as static lib." OFF) option(gtest_build_tests "Build all of gtest's own tests." OFF) option(gtest_build_samples "Build gtest's sample programs." OFF) option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) # Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). include(cmake/hermetic_build.cmake OPTIONAL) if (COMMAND pre_project_set_up_hermetic_build) pre_project_set_up_hermetic_build() endif() ######################################################################## # # Project-wide settings # Name of the project. # # CMake files in this project can refer to the root source directory # as ${gtest_SOURCE_DIR} and to the root binary directory as # ${gtest_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gtest CXX C) cmake_minimum_required(VERSION 2.6.2) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() # Define helper functions and macros used by Google Test. include(cmake/internal_utils.cmake) config_compiler_and_linker() # Defined in internal_utils.cmake. # Where Google Test's .h files can be found. include_directories( ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) # Where Google Test's libraries can be found. link_directories(${gtest_BINARY_DIR}/src) ######################################################################## # # Defines the gtest & gtest_main libraries. User tests should link # with one of them. # Google Test libraries. We build them using more strict warnings than what # are used for other targets, to ensure that gtest can be compiled by a user # aggressive about warnings. cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) target_link_libraries(gtest_main gtest) ######################################################################## # # Samples on how to link user tests with gtest or gtest_main. # # They are not built by default. To build them, set the # gtest_build_samples option to ON. You can do it by running ccmake # or specifying the -Dgtest_build_samples=ON flag when running cmake. if (gtest_build_samples) cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) cxx_executable(sample3_unittest samples gtest_main) cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) cxx_executable(sample6_unittest samples gtest_main) cxx_executable(sample7_unittest samples gtest_main) cxx_executable(sample8_unittest samples gtest_main) cxx_executable(sample9_unittest samples gtest) cxx_executable(sample10_unittest samples gtest) endif() ######################################################################## # # Google Test's own tests. # # You can skip this section if you aren't interested in testing # Google Test itself. # # The tests are not built by default. To build them, set the # gtest_build_tests option to ON. You can do it by running ccmake # or specifying the -Dgtest_build_tests=ON flag when running cmake. if (gtest_build_tests) # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() ############################################################ # C++ tests built with standard compiler flags. cxx_test(gtest-death-test_test gtest_main) cxx_test(gtest_environment_test gtest) cxx_test(gtest-filepath_test gtest_main) cxx_test(gtest-linked_ptr_test gtest_main) cxx_test(gtest-listener_test gtest_main) cxx_test(gtest_main_unittest gtest_main) cxx_test(gtest-message_test gtest_main) cxx_test(gtest_no_test_unittest gtest) cxx_test(gtest-options_test gtest_main) cxx_test(gtest-param-test_test gtest test/gtest-param-test2_test.cc) cxx_test(gtest-port_test gtest_main) cxx_test(gtest_pred_impl_unittest gtest_main) cxx_test(gtest_premature_exit_test gtest test/gtest_premature_exit_test.cc) cxx_test(gtest-printers_test gtest_main) cxx_test(gtest_prod_test gtest_main test/production.cc) cxx_test(gtest_repeat_test gtest) cxx_test(gtest_sole_header_test gtest_main) cxx_test(gtest_stress_test gtest) cxx_test(gtest-test-part_test gtest_main) cxx_test(gtest_throw_on_failure_ex_test gtest) cxx_test(gtest-typed-test_test gtest_main test/gtest-typed-test2_test.cc) cxx_test(gtest_unittest gtest_main) cxx_test(gtest-unittest-api_test gtest) ############################################################ # C++ tests built with non-standard compiler flags. # MSVC 7.1 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) cxx_library(gtest_no_exception "${cxx_no_exception}" src/gtest-all.cc) cxx_library(gtest_main_no_exception "${cxx_no_exception}" src/gtest-all.cc src/gtest_main.cc) endif() cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" src/gtest-all.cc src/gtest_main.cc) cxx_test_with_flags(gtest-death-test_ex_nocatch_test "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" gtest test/gtest-death-test_ex_test.cc) cxx_test_with_flags(gtest-death-test_ex_catch_test "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" gtest test/gtest-death-test_ex_test.cc) cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" gtest_main_no_rtti test/gtest_unittest.cc) cxx_shared_library(gtest_dll "${cxx_default}" src/gtest-all.cc src/gtest_main.cc) cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" gtest_dll test/gtest_all_test.cc) set_target_properties(gtest_dll_test_ PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600) # The C++ Standard specifies tuple_element. # Yet MSVC 10's declares tuple_element. # That declaration conflicts with our own standard-conforming # tuple implementation. Therefore using our own tuple with # MSVC 10 doesn't compile. cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}" src/gtest-all.cc src/gtest_main.cc) cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}" gtest_main_use_own_tuple test/gtest-tuple_test.cc) cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}" gtest_main_use_own_tuple test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) endif() ############################################################ # Python tests. cxx_executable(gtest_break_on_failure_unittest_ test gtest) py_test(gtest_break_on_failure_unittest) # MSVC 7.1 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) cxx_executable_with_flags( gtest_catch_exceptions_no_ex_test_ "${cxx_no_exception}" gtest_main_no_exception test/gtest_catch_exceptions_test_.cc) endif() cxx_executable_with_flags( gtest_catch_exceptions_ex_test_ "${cxx_exception}" gtest_main test/gtest_catch_exceptions_test_.cc) py_test(gtest_catch_exceptions_test) cxx_executable(gtest_color_test_ test gtest) py_test(gtest_color_test) cxx_executable(gtest_env_var_test_ test gtest) py_test(gtest_env_var_test) cxx_executable(gtest_filter_unittest_ test gtest) py_test(gtest_filter_unittest) cxx_executable(gtest_help_test_ test gtest_main) py_test(gtest_help_test) cxx_executable(gtest_list_tests_unittest_ test gtest) py_test(gtest_list_tests_unittest) cxx_executable(gtest_output_test_ test gtest) py_test(gtest_output_test) cxx_executable(gtest_shuffle_test_ test gtest) py_test(gtest_shuffle_test) # MSVC 7.1 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception) set_target_properties(gtest_throw_on_failure_test_ PROPERTIES COMPILE_FLAGS "${cxx_no_exception}") py_test(gtest_throw_on_failure_test) endif() cxx_executable(gtest_uninitialized_test_ test gtest) py_test(gtest_uninitialized_test) cxx_executable(gtest_xml_outfile1_test_ test gtest_main) cxx_executable(gtest_xml_outfile2_test_ test gtest_main) py_test(gtest_xml_outfiles_test) cxx_executable(gtest_xml_output_unittest_ test gtest) py_test(gtest_xml_output_unittest) endif() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/CONTRIBUTORS000066400000000000000000000025161273231111400247530ustar00rootroot00000000000000# This file contains a list of people who've made non-trivial # contribution to the Google C++ Testing Framework project. People # who commit code to the project are encouraged to add their names # here. Please keep the list sorted by first names. Ajay Joshi Balázs Dán Bharat Mediratta Chandler Carruth Chris Prince Chris Taylor Dan Egnor Eric Roman Hady Zalek Jeffrey Yasskin Jói Sigurðsson Keir Mierle Keith Ray Kenton Varda Manuel Klimek Markus Heule Mika Raento Miklós Fazekas Pasi Valminen Patrick Hanna Patrick Riley Peter Kaminski Preston Jackson Rainer Klaffenboeck Russ Cox Russ Rufer Sean Mcafee Sigurður Ásgeirsson Tracy Bialik Vadim Berman Vlad Losev Zhanyong Wan mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/LICENSE000066400000000000000000000027031273231111400240760ustar00rootroot00000000000000Copyright 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. mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/Makefile.am000066400000000000000000000230131273231111400251220ustar00rootroot00000000000000# Automake file ACLOCAL_AMFLAGS = -I m4 # Nonstandard package files for distribution EXTRA_DIST = \ CHANGES \ CONTRIBUTORS \ LICENSE \ include/gtest/gtest-param-test.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ include/gtest/internal/gtest-tuple.h.pump \ include/gtest/internal/gtest-type-util.h.pump \ make/Makefile \ scripts/fuse_gtest_files.py \ scripts/gen_gtest_pred_impl.py \ scripts/pump.py \ scripts/test/Makefile # gtest source files that we don't compile directly. They are # #included by gtest-all.cc. GTEST_SRC = \ src/gtest-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-printers.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc \ src/gtest.cc EXTRA_DIST += $(GTEST_SRC) # Sample files that we don't compile. EXTRA_DIST += \ samples/prime_tables.h \ samples/sample2_unittest.cc \ samples/sample3_unittest.cc \ samples/sample4_unittest.cc \ samples/sample5_unittest.cc \ samples/sample6_unittest.cc \ samples/sample7_unittest.cc \ samples/sample8_unittest.cc \ samples/sample9_unittest.cc # C++ test files that we don't compile directly. EXTRA_DIST += \ test/gtest-death-test_ex_test.cc \ test/gtest-death-test_test.cc \ test/gtest-filepath_test.cc \ test/gtest-linked_ptr_test.cc \ test/gtest-listener_test.cc \ test/gtest-message_test.cc \ test/gtest-options_test.cc \ test/gtest-param-test2_test.cc \ test/gtest-param-test2_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test_test.h \ test/gtest-port_test.cc \ test/gtest_premature_exit_test.cc \ test/gtest-printers_test.cc \ test/gtest-test-part_test.cc \ test/gtest-tuple_test.cc \ test/gtest-typed-test2_test.cc \ test/gtest-typed-test_test.cc \ test/gtest-typed-test_test.h \ test/gtest-unittest-api_test.cc \ test/gtest_break_on_failure_unittest_.cc \ test/gtest_catch_exceptions_test_.cc \ test/gtest_color_test_.cc \ test/gtest_env_var_test_.cc \ test/gtest_environment_test.cc \ test/gtest_filter_unittest_.cc \ test/gtest_help_test_.cc \ test/gtest_list_tests_unittest_.cc \ test/gtest_main_unittest.cc \ test/gtest_no_test_unittest.cc \ test/gtest_output_test_.cc \ test/gtest_pred_impl_unittest.cc \ test/gtest_prod_test.cc \ test/gtest_repeat_test.cc \ test/gtest_shuffle_test_.cc \ test/gtest_sole_header_test.cc \ test/gtest_stress_test.cc \ test/gtest_throw_on_failure_ex_test.cc \ test/gtest_throw_on_failure_test_.cc \ test/gtest_uninitialized_test_.cc \ test/gtest_unittest.cc \ test/gtest_unittest.cc \ test/gtest_xml_outfile1_test_.cc \ test/gtest_xml_outfile2_test_.cc \ test/gtest_xml_output_unittest_.cc \ test/production.cc \ test/production.h # Python tests that we don't run. EXTRA_DIST += \ test/gtest_break_on_failure_unittest.py \ test/gtest_catch_exceptions_test.py \ test/gtest_color_test.py \ test/gtest_env_var_test.py \ test/gtest_filter_unittest.py \ test/gtest_help_test.py \ test/gtest_list_tests_unittest.py \ test/gtest_output_test.py \ test/gtest_output_test_golden_lin.txt \ test/gtest_shuffle_test.py \ test/gtest_test_utils.py \ test/gtest_throw_on_failure_test.py \ test/gtest_uninitialized_test.py \ test/gtest_xml_outfiles_test.py \ test/gtest_xml_output_unittest.py \ test/gtest_xml_test_utils.py # CMake script EXTRA_DIST += \ CMakeLists.txt \ cmake/internal_utils.cmake # MSVC project files EXTRA_DIST += \ msvc/gtest-md.sln \ msvc/gtest-md.vcproj \ msvc/gtest.sln \ msvc/gtest.vcproj \ msvc/gtest_main-md.vcproj \ msvc/gtest_main.vcproj \ msvc/gtest_prod_test-md.vcproj \ msvc/gtest_prod_test.vcproj \ msvc/gtest_unittest-md.vcproj \ msvc/gtest_unittest.vcproj # xcode project files EXTRA_DIST += \ xcode/Config/DebugProject.xcconfig \ xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/General.xcconfig \ xcode/Config/ReleaseProject.xcconfig \ xcode/Config/StaticLibraryTarget.xcconfig \ xcode/Config/TestTarget.xcconfig \ xcode/Resources/Info.plist \ xcode/Scripts/runtests.sh \ xcode/Scripts/versiongenerate.py \ xcode/gtest.xcodeproj/project.pbxproj # xcode sample files EXTRA_DIST += \ xcode/Samples/FrameworkSample/Info.plist \ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \ xcode/Samples/FrameworkSample/runtests.sh \ xcode/Samples/FrameworkSample/widget.cc \ xcode/Samples/FrameworkSample/widget.h \ xcode/Samples/FrameworkSample/widget_test.cc # C++Builder project files EXTRA_DIST += \ codegear/gtest.cbproj \ codegear/gtest.groupproj \ codegear/gtest_all.cc \ codegear/gtest_link.cc \ codegear/gtest_main.cbproj \ codegear/gtest_unittest.cbproj # Distribute and install M4 macro m4datadir = $(datadir)/aclocal m4data_DATA = m4/gtest.m4 EXTRA_DIST += $(m4data_DATA) # We define the global AM_CPPFLAGS as everything we compile includes from these # directories. AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include # Modifies compiler and linker flags for pthreads compatibility. if HAVE_PTHREADS AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 AM_LIBS = @PTHREAD_LIBS@ else AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 endif # Build rules for libraries. lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la lib_libgtest_la_SOURCES = src/gtest-all.cc pkginclude_HEADERS = \ include/gtest/gtest-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest-printers.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ include/gtest/gtest-typed-test.h \ include/gtest/gtest.h \ include/gtest/gtest_pred_impl.h \ include/gtest/gtest_prod.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ 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 lib_libgtest_main_la_SOURCES = src/gtest_main.cc lib_libgtest_main_la_LIBADD = lib/libgtest.la # Bulid rules for samples and tests. Automake's naming for some of # these variables isn't terribly obvious, so this is a brief # reference: # # TESTS -- Programs run automatically by "make check" # check_PROGRAMS -- Programs built by "make check" but not necessarily run noinst_LTLIBRARIES = samples/libsamples.la samples_libsamples_la_SOURCES = \ samples/sample1.cc \ samples/sample1.h \ samples/sample2.cc \ samples/sample2.h \ samples/sample3-inl.h \ samples/sample4.cc \ samples/sample4.h TESTS= TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \ GTEST_BUILD_DIR="$(top_builddir)/test" check_PROGRAMS= # A simple sample on using gtest. TESTS += samples/sample1_unittest check_PROGRAMS += samples/sample1_unittest samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc samples_sample1_unittest_LDADD = lib/libgtest_main.la \ lib/libgtest.la \ samples/libsamples.la # Another sample. It also verifies that libgtest works. TESTS += samples/sample10_unittest check_PROGRAMS += samples/sample10_unittest samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc samples_sample10_unittest_LDADD = lib/libgtest.la # This tests most constructs of gtest and verifies that libgtest_main # and libgtest work. TESTS += test/gtest_all_test check_PROGRAMS += test/gtest_all_test test_gtest_all_test_SOURCES = test/gtest_all_test.cc test_gtest_all_test_LDADD = lib/libgtest_main.la \ lib/libgtest.la # Tests that fused gtest files compile and work. FUSED_GTEST_SRC = \ fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest.h \ fused-src/gtest/gtest_main.cc if HAVE_PYTHON TESTS += test/fused_gtest_test check_PROGRAMS += test/fused_gtest_test test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \ samples/sample1.cc samples/sample1_unittest.cc test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src" # Build rules for putting fused Google Test files into the distribution # package. The user can also create those files by manually running # scripts/fuse_gtest_files.py. $(test_fused_gtest_test_SOURCES): fused-gtest fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \ scripts/fuse_gtest_files.py mkdir -p "$(srcdir)/fused-src" chmod -R u+w "$(srcdir)/fused-src" rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" rm -f "$(srcdir)/fused-src/gtest/gtest.h" "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/" maintainer-clean-local: rm -rf "$(srcdir)/fused-src" endif # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES = core # Disables 'make install' as installing a compiled version of Google # Test can lead to undefined behavior due to violation of the # One-Definition Rule. install-exec-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false install-data-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/Makefile.in000066400000000000000000001632441273231111400251460ustar00rootroot00000000000000# Makefile.in generated by automake 1.11.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Automake file VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = samples/sample1_unittest$(EXEEXT) \ samples/sample10_unittest$(EXEEXT) \ test/gtest_all_test$(EXEEXT) $(am__EXEEXT_1) check_PROGRAMS = samples/sample1_unittest$(EXEEXT) \ samples/sample10_unittest$(EXEEXT) \ test/gtest_all_test$(EXEEXT) $(am__EXEEXT_1) @HAVE_PYTHON_TRUE@am__append_1 = test/fused_gtest_test @HAVE_PYTHON_TRUE@am__append_2 = test/fused_gtest_test subdir = . DIST_COMMON = README $(am__configure_deps) $(pkginclude_HEADERS) \ $(pkginclude_internal_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/build-aux/config.h.in \ $(top_srcdir)/configure $(top_srcdir)/scripts/gtest-config.in \ build-aux/config.guess build-aux/config.sub build-aux/depcomp \ build-aux/install-sh build-aux/ltmain.sh build-aux/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/acx_pthread.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/build-aux/config.h CONFIG_CLEAN_FILES = scripts/gtest-config CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" \ "$(DESTDIR)$(pkgincludedir)" \ "$(DESTDIR)$(pkginclude_internaldir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) lib_libgtest_la_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_lib_libgtest_la_OBJECTS = src/gtest-all.lo lib_libgtest_la_OBJECTS = $(am_lib_libgtest_la_OBJECTS) lib_libgtest_main_la_DEPENDENCIES = lib/libgtest.la am_lib_libgtest_main_la_OBJECTS = src/gtest_main.lo lib_libgtest_main_la_OBJECTS = $(am_lib_libgtest_main_la_OBJECTS) samples_libsamples_la_LIBADD = am_samples_libsamples_la_OBJECTS = samples/sample1.lo \ samples/sample2.lo samples/sample4.lo samples_libsamples_la_OBJECTS = $(am_samples_libsamples_la_OBJECTS) @HAVE_PYTHON_TRUE@am__EXEEXT_1 = test/fused_gtest_test$(EXEEXT) am_samples_sample10_unittest_OBJECTS = \ samples/sample10_unittest.$(OBJEXT) samples_sample10_unittest_OBJECTS = \ $(am_samples_sample10_unittest_OBJECTS) samples_sample10_unittest_DEPENDENCIES = lib/libgtest.la am_samples_sample1_unittest_OBJECTS = \ samples/sample1_unittest.$(OBJEXT) samples_sample1_unittest_OBJECTS = \ $(am_samples_sample1_unittest_OBJECTS) samples_sample1_unittest_DEPENDENCIES = lib/libgtest_main.la \ lib/libgtest.la samples/libsamples.la am__test_fused_gtest_test_SOURCES_DIST = fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest.h fused-src/gtest/gtest_main.cc \ samples/sample1.cc samples/sample1_unittest.cc am__objects_1 = \ fused-src/gtest/test_fused_gtest_test-gtest-all.$(OBJEXT) \ fused-src/gtest/test_fused_gtest_test-gtest_main.$(OBJEXT) @HAVE_PYTHON_TRUE@am_test_fused_gtest_test_OBJECTS = $(am__objects_1) \ @HAVE_PYTHON_TRUE@ samples/test_fused_gtest_test-sample1.$(OBJEXT) \ @HAVE_PYTHON_TRUE@ samples/test_fused_gtest_test-sample1_unittest.$(OBJEXT) test_fused_gtest_test_OBJECTS = $(am_test_fused_gtest_test_OBJECTS) test_fused_gtest_test_LDADD = $(LDADD) am_test_gtest_all_test_OBJECTS = test/gtest_all_test.$(OBJEXT) test_gtest_all_test_OBJECTS = $(am_test_gtest_all_test_OBJECTS) test_gtest_all_test_DEPENDENCIES = lib/libgtest_main.la \ lib/libgtest.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/build-aux depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(lib_libgtest_la_SOURCES) $(lib_libgtest_main_la_SOURCES) \ $(samples_libsamples_la_SOURCES) \ $(samples_sample10_unittest_SOURCES) \ $(samples_sample1_unittest_SOURCES) \ $(test_fused_gtest_test_SOURCES) \ $(test_gtest_all_test_SOURCES) DIST_SOURCES = $(lib_libgtest_la_SOURCES) \ $(lib_libgtest_main_la_SOURCES) \ $(samples_libsamples_la_SOURCES) \ $(samples_sample10_unittest_SOURCES) \ $(samples_sample1_unittest_SOURCES) \ $(am__test_fused_gtest_test_SOURCES_DIST) \ $(test_gtest_all_test_SOURCES) DATA = $(m4data_DATA) HEADERS = $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).zip GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PYTHON = @PYTHON@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 # Nonstandard package files for distribution # Sample files that we don't compile. # C++ test files that we don't compile directly. # Python tests that we don't run. # CMake script # MSVC project files # xcode project files # xcode sample files # C++Builder project files EXTRA_DIST = CHANGES CONTRIBUTORS LICENSE \ include/gtest/gtest-param-test.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ include/gtest/internal/gtest-tuple.h.pump \ include/gtest/internal/gtest-type-util.h.pump make/Makefile \ scripts/fuse_gtest_files.py scripts/gen_gtest_pred_impl.py \ scripts/pump.py scripts/test/Makefile $(GTEST_SRC) \ samples/prime_tables.h samples/sample2_unittest.cc \ samples/sample3_unittest.cc samples/sample4_unittest.cc \ samples/sample5_unittest.cc samples/sample6_unittest.cc \ samples/sample7_unittest.cc samples/sample8_unittest.cc \ samples/sample9_unittest.cc test/gtest-death-test_ex_test.cc \ test/gtest-death-test_test.cc test/gtest-filepath_test.cc \ test/gtest-linked_ptr_test.cc test/gtest-listener_test.cc \ test/gtest-message_test.cc test/gtest-options_test.cc \ test/gtest-param-test2_test.cc test/gtest-param-test2_test.cc \ test/gtest-param-test_test.cc test/gtest-param-test_test.cc \ test/gtest-param-test_test.h test/gtest-port_test.cc \ test/gtest_premature_exit_test.cc test/gtest-printers_test.cc \ test/gtest-test-part_test.cc test/gtest-tuple_test.cc \ test/gtest-typed-test2_test.cc test/gtest-typed-test_test.cc \ test/gtest-typed-test_test.h test/gtest-unittest-api_test.cc \ test/gtest_break_on_failure_unittest_.cc \ test/gtest_catch_exceptions_test_.cc test/gtest_color_test_.cc \ test/gtest_env_var_test_.cc test/gtest_environment_test.cc \ test/gtest_filter_unittest_.cc test/gtest_help_test_.cc \ test/gtest_list_tests_unittest_.cc test/gtest_main_unittest.cc \ test/gtest_no_test_unittest.cc test/gtest_output_test_.cc \ test/gtest_pred_impl_unittest.cc test/gtest_prod_test.cc \ test/gtest_repeat_test.cc test/gtest_shuffle_test_.cc \ test/gtest_sole_header_test.cc test/gtest_stress_test.cc \ test/gtest_throw_on_failure_ex_test.cc \ test/gtest_throw_on_failure_test_.cc \ test/gtest_uninitialized_test_.cc test/gtest_unittest.cc \ test/gtest_unittest.cc test/gtest_xml_outfile1_test_.cc \ test/gtest_xml_outfile2_test_.cc \ test/gtest_xml_output_unittest_.cc test/production.cc \ test/production.h test/gtest_break_on_failure_unittest.py \ test/gtest_catch_exceptions_test.py test/gtest_color_test.py \ test/gtest_env_var_test.py test/gtest_filter_unittest.py \ test/gtest_help_test.py test/gtest_list_tests_unittest.py \ test/gtest_output_test.py \ test/gtest_output_test_golden_lin.txt \ test/gtest_shuffle_test.py test/gtest_test_utils.py \ test/gtest_throw_on_failure_test.py \ test/gtest_uninitialized_test.py \ test/gtest_xml_outfiles_test.py \ test/gtest_xml_output_unittest.py test/gtest_xml_test_utils.py \ CMakeLists.txt cmake/internal_utils.cmake msvc/gtest-md.sln \ msvc/gtest-md.vcproj msvc/gtest.sln msvc/gtest.vcproj \ msvc/gtest_main-md.vcproj msvc/gtest_main.vcproj \ msvc/gtest_prod_test-md.vcproj msvc/gtest_prod_test.vcproj \ msvc/gtest_unittest-md.vcproj msvc/gtest_unittest.vcproj \ xcode/Config/DebugProject.xcconfig \ xcode/Config/FrameworkTarget.xcconfig \ xcode/Config/General.xcconfig \ xcode/Config/ReleaseProject.xcconfig \ xcode/Config/StaticLibraryTarget.xcconfig \ xcode/Config/TestTarget.xcconfig xcode/Resources/Info.plist \ xcode/Scripts/runtests.sh xcode/Scripts/versiongenerate.py \ xcode/gtest.xcodeproj/project.pbxproj \ xcode/Samples/FrameworkSample/Info.plist \ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \ xcode/Samples/FrameworkSample/runtests.sh \ xcode/Samples/FrameworkSample/widget.cc \ xcode/Samples/FrameworkSample/widget.h \ xcode/Samples/FrameworkSample/widget_test.cc \ codegear/gtest.cbproj codegear/gtest.groupproj \ codegear/gtest_all.cc codegear/gtest_link.cc \ codegear/gtest_main.cbproj codegear/gtest_unittest.cbproj \ $(m4data_DATA) # gtest source files that we don't compile directly. They are # #included by gtest-all.cc. GTEST_SRC = \ src/gtest-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-printers.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc \ src/gtest.cc # Distribute and install M4 macro m4datadir = $(datadir)/aclocal m4data_DATA = m4/gtest.m4 # We define the global AM_CPPFLAGS as everything we compile includes from these # directories. AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include @HAVE_PTHREADS_FALSE@AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 # Modifies compiler and linker flags for pthreads compatibility. @HAVE_PTHREADS_TRUE@AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 @HAVE_PTHREADS_TRUE@AM_LIBS = @PTHREAD_LIBS@ # Build rules for libraries. lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la lib_libgtest_la_SOURCES = src/gtest-all.cc pkginclude_HEADERS = \ include/gtest/gtest-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest-printers.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ include/gtest/gtest-typed-test.h \ include/gtest/gtest.h \ include/gtest/gtest_pred_impl.h \ include/gtest/gtest_prod.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ 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 lib_libgtest_main_la_SOURCES = src/gtest_main.cc lib_libgtest_main_la_LIBADD = lib/libgtest.la # Bulid rules for samples and tests. Automake's naming for some of # these variables isn't terribly obvious, so this is a brief # reference: # # TESTS -- Programs run automatically by "make check" # check_PROGRAMS -- Programs built by "make check" but not necessarily run noinst_LTLIBRARIES = samples/libsamples.la samples_libsamples_la_SOURCES = \ samples/sample1.cc \ samples/sample1.h \ samples/sample2.cc \ samples/sample2.h \ samples/sample3-inl.h \ samples/sample4.cc \ samples/sample4.h TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \ GTEST_BUILD_DIR="$(top_builddir)/test" samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc samples_sample1_unittest_LDADD = lib/libgtest_main.la \ lib/libgtest.la \ samples/libsamples.la samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc samples_sample10_unittest_LDADD = lib/libgtest.la test_gtest_all_test_SOURCES = test/gtest_all_test.cc test_gtest_all_test_LDADD = lib/libgtest_main.la \ lib/libgtest.la # Tests that fused gtest files compile and work. FUSED_GTEST_SRC = \ fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest.h \ fused-src/gtest/gtest_main.cc @HAVE_PYTHON_TRUE@test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \ @HAVE_PYTHON_TRUE@ samples/sample1.cc samples/sample1_unittest.cc @HAVE_PYTHON_TRUE@test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src" # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES = core all: all-am .SUFFIXES: .SUFFIXES: .cc .lo .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): build-aux/config.h: build-aux/stamp-h1 @if test ! -f $@; then rm -f build-aux/stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) build-aux/stamp-h1; else :; fi build-aux/stamp-h1: $(top_srcdir)/build-aux/config.h.in $(top_builddir)/config.status @rm -f build-aux/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status build-aux/config.h $(top_srcdir)/build-aux/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f build-aux/stamp-h1 touch $@ distclean-hdr: -rm -f build-aux/config.h build-aux/stamp-h1 scripts/gtest-config: $(top_builddir)/config.status $(top_srcdir)/scripts/gtest-config.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done src/$(am__dirstamp): @$(MKDIR_P) src @: > src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/$(DEPDIR) @: > src/$(DEPDIR)/$(am__dirstamp) src/gtest-all.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) lib/$(am__dirstamp): @$(MKDIR_P) lib @: > lib/$(am__dirstamp) lib/libgtest.la: $(lib_libgtest_la_OBJECTS) $(lib_libgtest_la_DEPENDENCIES) $(EXTRA_lib_libgtest_la_DEPENDENCIES) lib/$(am__dirstamp) $(CXXLINK) -rpath $(libdir) $(lib_libgtest_la_OBJECTS) $(lib_libgtest_la_LIBADD) $(LIBS) src/gtest_main.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) lib/libgtest_main.la: $(lib_libgtest_main_la_OBJECTS) $(lib_libgtest_main_la_DEPENDENCIES) $(EXTRA_lib_libgtest_main_la_DEPENDENCIES) lib/$(am__dirstamp) $(CXXLINK) -rpath $(libdir) $(lib_libgtest_main_la_OBJECTS) $(lib_libgtest_main_la_LIBADD) $(LIBS) samples/$(am__dirstamp): @$(MKDIR_P) samples @: > samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) samples/$(DEPDIR) @: > samples/$(DEPDIR)/$(am__dirstamp) samples/sample1.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample2.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample4.lo: samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/libsamples.la: $(samples_libsamples_la_OBJECTS) $(samples_libsamples_la_DEPENDENCIES) $(EXTRA_samples_libsamples_la_DEPENDENCIES) samples/$(am__dirstamp) $(CXXLINK) $(samples_libsamples_la_OBJECTS) $(samples_libsamples_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list samples/sample10_unittest.$(OBJEXT): samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample10_unittest$(EXEEXT): $(samples_sample10_unittest_OBJECTS) $(samples_sample10_unittest_DEPENDENCIES) $(EXTRA_samples_sample10_unittest_DEPENDENCIES) samples/$(am__dirstamp) @rm -f samples/sample10_unittest$(EXEEXT) $(CXXLINK) $(samples_sample10_unittest_OBJECTS) $(samples_sample10_unittest_LDADD) $(LIBS) samples/sample1_unittest.$(OBJEXT): samples/$(am__dirstamp) \ samples/$(DEPDIR)/$(am__dirstamp) samples/sample1_unittest$(EXEEXT): $(samples_sample1_unittest_OBJECTS) $(samples_sample1_unittest_DEPENDENCIES) $(EXTRA_samples_sample1_unittest_DEPENDENCIES) samples/$(am__dirstamp) @rm -f samples/sample1_unittest$(EXEEXT) $(CXXLINK) $(samples_sample1_unittest_OBJECTS) $(samples_sample1_unittest_LDADD) $(LIBS) fused-src/gtest/$(am__dirstamp): @$(MKDIR_P) fused-src/gtest @: > fused-src/gtest/$(am__dirstamp) fused-src/gtest/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) fused-src/gtest/$(DEPDIR) @: > fused-src/gtest/$(DEPDIR)/$(am__dirstamp) fused-src/gtest/test_fused_gtest_test-gtest-all.$(OBJEXT): \ fused-src/gtest/$(am__dirstamp) \ fused-src/gtest/$(DEPDIR)/$(am__dirstamp) fused-src/gtest/test_fused_gtest_test-gtest_main.$(OBJEXT): \ fused-src/gtest/$(am__dirstamp) \ fused-src/gtest/$(DEPDIR)/$(am__dirstamp) samples/test_fused_gtest_test-sample1.$(OBJEXT): \ samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp) samples/test_fused_gtest_test-sample1_unittest.$(OBJEXT): \ samples/$(am__dirstamp) samples/$(DEPDIR)/$(am__dirstamp) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/fused_gtest_test$(EXEEXT): $(test_fused_gtest_test_OBJECTS) $(test_fused_gtest_test_DEPENDENCIES) $(EXTRA_test_fused_gtest_test_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/fused_gtest_test$(EXEEXT) $(CXXLINK) $(test_fused_gtest_test_OBJECTS) $(test_fused_gtest_test_LDADD) $(LIBS) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/gtest_all_test.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/gtest_all_test$(EXEEXT): $(test_gtest_all_test_OBJECTS) $(test_gtest_all_test_DEPENDENCIES) $(EXTRA_test_gtest_all_test_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/gtest_all_test$(EXEEXT) $(CXXLINK) $(test_gtest_all_test_OBJECTS) $(test_gtest_all_test_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f fused-src/gtest/test_fused_gtest_test-gtest-all.$(OBJEXT) -rm -f fused-src/gtest/test_fused_gtest_test-gtest_main.$(OBJEXT) -rm -f samples/sample1.$(OBJEXT) -rm -f samples/sample1.lo -rm -f samples/sample10_unittest.$(OBJEXT) -rm -f samples/sample1_unittest.$(OBJEXT) -rm -f samples/sample2.$(OBJEXT) -rm -f samples/sample2.lo -rm -f samples/sample4.$(OBJEXT) -rm -f samples/sample4.lo -rm -f samples/test_fused_gtest_test-sample1.$(OBJEXT) -rm -f samples/test_fused_gtest_test-sample1_unittest.$(OBJEXT) -rm -f src/gtest-all.$(OBJEXT) -rm -f src/gtest-all.lo -rm -f src/gtest_main.$(OBJEXT) -rm -f src/gtest_main.lo -rm -f test/gtest_all_test.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample10_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample1_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/sample4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/gtest-all.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/gtest_main.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/gtest_all_test.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< fused-src/gtest/test_fused_gtest_test-gtest-all.o: fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest-all.o -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.o `test -f 'fused-src/gtest/gtest-all.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fused-src/gtest/gtest-all.cc' object='fused-src/gtest/test_fused_gtest_test-gtest-all.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.o `test -f 'fused-src/gtest/gtest-all.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest-all.cc fused-src/gtest/test_fused_gtest_test-gtest-all.obj: fused-src/gtest/gtest-all.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest-all.obj -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.obj `if test -f 'fused-src/gtest/gtest-all.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest-all.cc'; fi` @am__fastdepCXX_TRUE@ $(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fused-src/gtest/gtest-all.cc' object='fused-src/gtest/test_fused_gtest_test-gtest-all.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest-all.obj `if test -f 'fused-src/gtest/gtest-all.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest-all.cc'; fi` fused-src/gtest/test_fused_gtest_test-gtest_main.o: fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest_main.o -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.o `test -f 'fused-src/gtest/gtest_main.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fused-src/gtest/gtest_main.cc' object='fused-src/gtest/test_fused_gtest_test-gtest_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.o `test -f 'fused-src/gtest/gtest_main.cc' || echo '$(srcdir)/'`fused-src/gtest/gtest_main.cc fused-src/gtest/test_fused_gtest_test-gtest_main.obj: fused-src/gtest/gtest_main.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fused-src/gtest/test_fused_gtest_test-gtest_main.obj -MD -MP -MF fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.obj `if test -f 'fused-src/gtest/gtest_main.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest_main.cc'; fi` @am__fastdepCXX_TRUE@ $(am__mv) fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Tpo fused-src/gtest/$(DEPDIR)/test_fused_gtest_test-gtest_main.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fused-src/gtest/gtest_main.cc' object='fused-src/gtest/test_fused_gtest_test-gtest_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fused-src/gtest/test_fused_gtest_test-gtest_main.obj `if test -f 'fused-src/gtest/gtest_main.cc'; then $(CYGPATH_W) 'fused-src/gtest/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/fused-src/gtest/gtest_main.cc'; fi` samples/test_fused_gtest_test-sample1.o: samples/sample1.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1.o -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo -c -o samples/test_fused_gtest_test-sample1.o `test -f 'samples/sample1.cc' || echo '$(srcdir)/'`samples/sample1.cc @am__fastdepCXX_TRUE@ $(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='samples/sample1.cc' object='samples/test_fused_gtest_test-sample1.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1.o `test -f 'samples/sample1.cc' || echo '$(srcdir)/'`samples/sample1.cc samples/test_fused_gtest_test-sample1.obj: samples/sample1.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1.obj -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo -c -o samples/test_fused_gtest_test-sample1.obj `if test -f 'samples/sample1.cc'; then $(CYGPATH_W) 'samples/sample1.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1.cc'; fi` @am__fastdepCXX_TRUE@ $(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='samples/sample1.cc' object='samples/test_fused_gtest_test-sample1.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1.obj `if test -f 'samples/sample1.cc'; then $(CYGPATH_W) 'samples/sample1.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1.cc'; fi` samples/test_fused_gtest_test-sample1_unittest.o: samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1_unittest.o -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo -c -o samples/test_fused_gtest_test-sample1_unittest.o `test -f 'samples/sample1_unittest.cc' || echo '$(srcdir)/'`samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='samples/sample1_unittest.cc' object='samples/test_fused_gtest_test-sample1_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1_unittest.o `test -f 'samples/sample1_unittest.cc' || echo '$(srcdir)/'`samples/sample1_unittest.cc samples/test_fused_gtest_test-sample1_unittest.obj: samples/sample1_unittest.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT samples/test_fused_gtest_test-sample1_unittest.obj -MD -MP -MF samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo -c -o samples/test_fused_gtest_test-sample1_unittest.obj `if test -f 'samples/sample1_unittest.cc'; then $(CYGPATH_W) 'samples/sample1_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(am__mv) samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Tpo samples/$(DEPDIR)/test_fused_gtest_test-sample1_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='samples/sample1_unittest.cc' object='samples/test_fused_gtest_test-sample1_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_fused_gtest_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o samples/test_fused_gtest_test-sample1_unittest.obj `if test -f 'samples/sample1_unittest.cc'; then $(CYGPATH_W) 'samples/sample1_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/samples/sample1_unittest.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf lib/.libs lib/_libs -rm -rf samples/.libs samples/_libs -rm -rf src/.libs src/_libs -rm -rf test/.libs test/_libs distclean-libtool: -rm -f libtool config.lt install-m4dataDATA: $(m4data_DATA) @$(NORMAL_INSTALL) test -z "$(m4datadir)" || $(MKDIR_P) "$(DESTDIR)$(m4datadir)" @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \ done uninstall-m4dataDATA: @$(NORMAL_UNINSTALL) @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(m4datadir)'; $(am__uninstall_files_from_dir) install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(pkgincludedir)" || $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) install-pkginclude_internalHEADERS: $(pkginclude_internal_HEADERS) @$(NORMAL_INSTALL) test -z "$(pkginclude_internaldir)" || $(MKDIR_P) "$(DESTDIR)$(pkginclude_internaldir)" @list='$(pkginclude_internal_HEADERS)'; test -n "$(pkginclude_internaldir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginclude_internaldir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginclude_internaldir)" || exit $$?; \ done uninstall-pkginclude_internalHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_internal_HEADERS)'; test -n "$(pkginclude_internaldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkginclude_internaldir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ col="$$grn"; \ else \ col="$$red"; \ fi; \ echo "$${col}$$dashes$${std}"; \ echo "$${col}$$banner$${std}"; \ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ test -z "$$report" || echo "$${col}$$report$${std}"; \ echo "$${col}$$dashes$${std}"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkginclude_internaldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f fused-src/gtest/$(DEPDIR)/$(am__dirstamp) -rm -f fused-src/gtest/$(am__dirstamp) -rm -f lib/$(am__dirstamp) -rm -f samples/$(DEPDIR)/$(am__dirstamp) -rm -f samples/$(am__dirstamp) -rm -f src/$(DEPDIR)/$(am__dirstamp) -rm -f src/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @HAVE_PYTHON_FALSE@maintainer-clean-local: clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf fused-src/gtest/$(DEPDIR) samples/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-m4dataDATA \ install-pkgincludeHEADERS install-pkginclude_internalHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-exec-local install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf fused-src/gtest/$(DEPDIR) samples/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic \ maintainer-clean-local mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-m4dataDATA \ uninstall-pkgincludeHEADERS \ uninstall-pkginclude_internalHEADERS .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ clean clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstLTLIBRARIES ctags dist dist-all \ dist-bzip2 dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ \ dist-xz dist-zip distcheck distclean distclean-compile \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-data-local install-dvi \ install-dvi-am install-exec install-exec-am install-exec-local \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-m4dataDATA install-man \ install-pdf install-pdf-am install-pkgincludeHEADERS \ install-pkginclude_internalHEADERS install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic \ maintainer-clean-local mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-m4dataDATA uninstall-pkgincludeHEADERS \ uninstall-pkginclude_internalHEADERS # Build rules for putting fused Google Test files into the distribution # package. The user can also create those files by manually running # scripts/fuse_gtest_files.py. @HAVE_PYTHON_TRUE@$(test_fused_gtest_test_SOURCES): fused-gtest @HAVE_PYTHON_TRUE@fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ @HAVE_PYTHON_TRUE@ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \ @HAVE_PYTHON_TRUE@ scripts/fuse_gtest_files.py @HAVE_PYTHON_TRUE@ mkdir -p "$(srcdir)/fused-src" @HAVE_PYTHON_TRUE@ chmod -R u+w "$(srcdir)/fused-src" @HAVE_PYTHON_TRUE@ rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" @HAVE_PYTHON_TRUE@ rm -f "$(srcdir)/fused-src/gtest/gtest.h" @HAVE_PYTHON_TRUE@ "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" @HAVE_PYTHON_TRUE@ cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/" @HAVE_PYTHON_TRUE@maintainer-clean-local: @HAVE_PYTHON_TRUE@ rm -rf "$(srcdir)/fused-src" # Disables 'make install' as installing a compiled version of Google # Test can lead to undefined behavior due to violation of the # One-Definition Rule. install-exec-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false install-data-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/README000066400000000000000000000373321273231111400237570ustar00rootroot00000000000000Google C++ Testing Framework ============================ http://code.google.com/p/googletest/ Overview -------- Google's framework for writing C++ tests on a variety of platforms (Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the xUnit architecture. Supports automatic test discovery, a rich set of assertions, user-defined assertions, death tests, fatal and non-fatal failures, various options for running the tests, and XML test report generation. Please see the project page above for more information as well as the mailing list for questions, discussions, and development. There is also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please join us! Requirements for End Users -------------------------- Google Test is designed to have fairly minimal requirements to build and use with your projects, but there are some. Currently, we support Linux, Windows, Mac OS X, and Cygwin. We will also make our best effort to support other platforms (e.g. Solaris, AIX, and z/OS). However, since core members of the Google Test project have no access to these platforms, Google Test may have outstanding issues there. If you notice any problems on your platform, please notify googletestframework@googlegroups.com. Patches for fixing them are even more welcome! ### Linux Requirements ### These are the base requirements to build and use Google Test from a source package (as described below): * GNU-compatible Make or gmake * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) * A C++98-standard-compliant compiler ### Windows Requirements ### * Microsoft Visual C++ 7.1 or newer ### Cygwin Requirements ### * Cygwin 1.5.25-14 or newer ### Mac OS X Requirements ### * Mac OS X 10.4 Tiger or newer * Developer Tools Installed Also, you'll need CMake 2.6.4 or higher if you want to build the samples using the provided CMake script, regardless of the platform. Requirements for Contributors ----------------------------- We welcome patches. If you plan to contribute a patch, you need to build Google Test and its own tests from an SVN checkout (described below), which has further requirements: * Python version 2.3 or newer (for running some of the tests and re-generating certain source files from templates) * CMake 2.6.4 or newer Getting the Source ------------------ There are two primary ways of getting Google Test's source code: you can download a stable source release in your preferred archive format, or directly check out the source from our Subversion (SVN) repositary. The SVN checkout requires a few extra steps and some extra software packages on your system, but lets you track the latest development and make patches much more easily, so we highly encourage it. ### Source Package ### Google Test is released in versioned source packages which can be downloaded from the download page [1]. Several different archive formats are provided, but the only difference is the tools used to manipulate them, and the size of the resulting file. Download whichever you are most comfortable with. [1] http://code.google.com/p/googletest/downloads/list Once the package is downloaded, expand it using whichever tools you prefer for that type. This will result in a new directory with the name "gtest-X.Y.Z" which contains all of the source code. Here are some examples on Linux: tar -xvzf gtest-X.Y.Z.tar.gz tar -xvjf gtest-X.Y.Z.tar.bz2 unzip gtest-X.Y.Z.zip ### SVN Checkout ### To check out the main branch (also known as the "trunk") of Google Test, run the following Subversion command: svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn Setting up the Build -------------------- To build Google Test and your tests that use it, you need to tell your build system where to find its headers and source files. The exact way to do it depends on which build system you use, and is usually straightforward. ### Generic Build Instructions ### Suppose you put Google Test in directory ${GTEST_DIR}. To build it, create a library build target (or a project as called by Visual Studio and Xcode) to compile ${GTEST_DIR}/src/gtest-all.cc with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR} in the normal header search path. Assuming a Linux-like system and gcc, something like the following will do: g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ -pthread -c ${GTEST_DIR}/src/gtest-all.cc ar -rv libgtest.a gtest-all.o (We need -pthread as Google Test uses threads.) Next, you should compile your test source file with ${GTEST_DIR}/include in the system header search path, and link it with gtest and any other necessary libraries: g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \ -o your_test As an example, the make/ directory contains a Makefile that you can use to build Google Test on systems where GNU make is available (e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google Test's own tests. Instead, it just builds the Google Test library and a sample test. You can use it as a starting point for your own build script. If the default settings are correct for your environment, the following commands should succeed: cd ${GTEST_DIR}/make make ./sample1_unittest If you see errors, try to tweak the contents of make/Makefile to make them go away. There are instructions in make/Makefile on how to do it. ### Using CMake ### Google Test comes with a CMake build script (CMakeLists.txt) that can be used on a wide range of platforms ("C" stands for cross-platofrm.). If you don't have CMake installed already, you can download it for free from http://www.cmake.org/. CMake works by generating native makefiles or build projects that can be used in the compiler environment of your choice. The typical workflow starts with: mkdir mybuild # Create a directory to hold the build output. cd mybuild cmake ${GTEST_DIR} # Generate native build scripts. If you want to build Google Test's samples, you should replace the last command with cmake -Dgtest_build_samples=ON ${GTEST_DIR} If you are on a *nix system, you should now see a Makefile in the current directory. Just type 'make' to build gtest. If you use Windows and have Vistual Studio installed, a gtest.sln file and several .vcproj files will be created. You can then build them using Visual Studio. On Mac OS X with Xcode installed, a .xcodeproj file will be generated. ### Legacy Build Scripts ### Before settling on CMake, we have been providing hand-maintained build projects/scripts for Visual Studio, Xcode, and Autotools. While we continue to provide them for convenience, they are not actively maintained any more. We highly recommend that you follow the instructions in the previous two sections to integrate Google Test with your existing build system. If you still need to use the legacy build scripts, here's how: The msvc\ folder contains two solutions with Visual C++ projects. Open the gtest.sln or gtest-md.sln file using Visual Studio, and you are ready to build Google Test the same way you build any Visual Studio project. Files that have names ending with -md use DLL versions of Microsoft runtime libraries (the /MD or the /MDd compiler option). Files without that suffix use static versions of the runtime libraries (the /MT or the /MTd option). Please note that one must use the same option to compile both gtest and the test code. If you use Visual Studio 2005 or above, we recommend the -md version as /MD is the default for new projects in these versions of Visual Studio. On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using Xcode. Build the "gtest" target. The universal binary framework will end up in your selected build directory (selected in the Xcode "Preferences..." -> "Building" pane and defaults to xcode/build). Alternatively, at the command line, enter: xcodebuild This will build the "Release" configuration of gtest.framework in your default build location. See the "xcodebuild" man page for more information about building different configurations and building in different locations. If you wish to use the Google Test Xcode project with Xcode 4.x and above, you need to either: * update the SDK configuration options in xcode/Config/General.xconfig. Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If you choose this route you lose the ability to target earlier versions of MacOS X. * Install an SDK for an earlier version. This doesn't appear to be supported by Apple, but has been reported to work (http://stackoverflow.com/questions/5378518). Tweaking Google Test -------------------- Google Test can be used in diverse environments. The default configuration may not work (or may not work well) out of the box in some environments. However, you can easily tweak Google Test by defining control macros on the compiler command line. Generally, these macros are named like GTEST_XYZ and you define them to either 1 or 0 to enable or disable a certain feature. We list the most frequently used macros below. For a complete list, see file include/gtest/internal/gtest-port.h. ### Choosing a TR1 Tuple Library ### Some Google Test features require the C++ Technical Report 1 (TR1) tuple library, which is not yet available with all compilers. The good news is that Google Test implements a subset of TR1 tuple that's enough for its own need, and will automatically use this when the compiler doesn't provide TR1 tuple. Usually you don't need to care about which tuple library Google Test uses. However, if your project already uses TR1 tuple, you need to tell Google Test to use the same TR1 tuple library the rest of your project uses, or the two tuple implementations will clash. To do that, add -DGTEST_USE_OWN_TR1_TUPLE=0 to the compiler flags while compiling Google Test and your tests. If you want to force Google Test to use its own tuple library, just add -DGTEST_USE_OWN_TR1_TUPLE=1 to the compiler flags instead. If you don't want Google Test to use tuple at all, add -DGTEST_HAS_TR1_TUPLE=0 and all features using tuple will be disabled. ### Multi-threaded Tests ### Google Test is thread-safe where the pthread library is available. After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE macro to see whether this is the case (yes if the macro is #defined to 1, no if it's undefined.). If Google Test doesn't correctly detect whether pthread is available in your environment, you can force it with -DGTEST_HAS_PTHREAD=1 or -DGTEST_HAS_PTHREAD=0 When Google Test uses pthread, you may need to add flags to your compiler and/or linker to select the pthread library, or you'll get link errors. If you use the CMake script or the deprecated Autotools script, this is taken care of for you. If you use your own build script, you'll need to read your compiler and linker's manual to figure out what flags to add. ### As a Shared Library (DLL) ### Google Test is compact, so most users can build and link it as a static library for the simplicity. You can choose to use Google Test as a shared library (known as a DLL on Windows) if you prefer. To compile *gtest* as a shared library, add -DGTEST_CREATE_SHARED_LIBRARY=1 to the compiler flags. You'll also need to tell the linker to produce a shared library instead - consult your linker's manual for how to do it. To compile your *tests* that use the gtest shared library, add -DGTEST_LINKED_AS_SHARED_LIBRARY=1 to the compiler flags. Note: while the above steps aren't technically necessary today when using some compilers (e.g. GCC), they may become necessary in the future, if we decide to improve the speed of loading the library (see http://gcc.gnu.org/wiki/Visibility for details). Therefore you are recommended to always add the above flags when using Google Test as a shared library. Otherwise a future release of Google Test may break your build script. ### Avoiding Macro Name Clashes ### In C++, macros don't obey namespaces. Therefore two libraries that both define a macro of the same name will clash if you #include both definitions. In case a Google Test macro clashes with another library, you can force Google Test to rename its macro to avoid the conflict. Specifically, if both Google Test and some other code define macro FOO, you can add -DGTEST_DONT_DEFINE_FOO=1 to the compiler flags to tell Google Test to change the macro's name from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST. For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write GTEST_TEST(SomeTest, DoesThis) { ... } instead of TEST(SomeTest, DoesThis) { ... } in order to define a test. Upgrating from an Earlier Version --------------------------------- We strive to keep Google Test releases backward compatible. Sometimes, though, we have to make some breaking changes for the users' long-term benefits. This section describes what you'll need to do if you are upgrading from an earlier version of Google Test. ### Upgrading from 1.3.0 or Earlier ### You may need to explicitly enable or disable Google Test's own TR1 tuple library. See the instructions in section "Choosing a TR1 Tuple Library". ### Upgrading from 1.4.0 or Earlier ### The Autotools build script (configure + make) is no longer officially supportted. You are encouraged to migrate to your own build system or use CMake. If you still need to use Autotools, you can find instructions in the README file from Google Test 1.4.0. On platforms where the pthread library is available, Google Test uses it in order to be thread-safe. See the "Multi-threaded Tests" section for what this means to your build script. If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google Test will no longer compile. This should affect very few people, as a large portion of STL (including ) doesn't compile in this mode anyway. We decided to stop supporting it in order to greatly simplify Google Test's implementation. Developing Google Test ---------------------- This section discusses how to make your own changes to Google Test. ### Testing Google Test Itself ### To make sure your changes work as intended and don't break existing functionality, you'll want to compile and run Google Test's own tests. For that you can use CMake: mkdir mybuild cd mybuild cmake -Dgtest_build_tests=ON ${GTEST_DIR} Make sure you have Python installed, as some of Google Test's tests are written in Python. If the cmake command complains about not being able to find Python ("Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)"), try telling it explicitly where your Python executable can be found: cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR} Next, you can build Google Test and all of its own tests. On *nix, this is usually done by 'make'. To run the tests, do make test All tests should pass. ### Regenerating Source Files ### Some of Google Test's source files are generated from templates (not in the C++ sense) using a script. A template file is named FOO.pump, where FOO is the name of the file it will generate. For example, the file include/gtest/internal/gtest-type-util.h.pump is used to generate gtest-type-util.h in the same directory. Normally you don't need to worry about regenerating the source files, unless you need to modify them. In that case, you should modify the corresponding .pump files instead and run the pump.py Python script to regenerate them. You can find pump.py in the scripts/ directory. Read the Pump manual [2] for how to use it. [2] http://code.google.com/p/googletest/wiki/PumpManual ### Contributing a Patch ### We welcome patches. Please read the Google Test developer's guide [3] for how you can contribute. In particular, make sure you have signed the Contributor License Agreement, or we won't be able to accept the patch. [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide Happy testing! mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/SConscript000066400000000000000000000007451273231111400251070ustar00rootroot00000000000000Import('env') gtestEnv = env.Clone() gtestEnv.AppendUnique(CPPPATH=['$VARIANT_DIR/third_party/gtest-1.7.0']) libGTestStatic = gtestEnv.StaticLibrary( target='gtest', source=[ 'src/gtest-all.cc', ], ) libGTestMainStatic = gtestEnv.StaticLibrary( target='gtest_main', source=[ 'src/gtest_main.cc', ], LIBS=[ libGTestStatic, ], ) Export({ 'libGTestStatic' : libGTestStatic, 'libGTestMainStatic' : libGTestMainStatic, }) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/aclocal.m4000066400000000000000000001253711273231111400247400ustar00rootroot00000000000000# generated automatically by aclocal 1.11.3 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, # Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, [m4_warning([this file was generated for autoconf 2.68. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, # 2010, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, # 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.2 python3.1 python3.0 python2.7 dnl python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) AC_ARG_VAR([PYTHON], [the Python interpreter]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT(yes)], [AC_MSG_ERROR(too old)]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/000077500000000000000000000000001273231111400247615ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/config.guess000077500000000000000000001274321273231111400273120ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/config.h.in000066400000000000000000000034611273231111400270100ustar00rootroot00000000000000/* build-aux/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/config.sub000077500000000000000000001051761273231111400267560ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/depcomp000077500000000000000000000475561273231111400263570ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2011-12-04.11; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011 Free Software Foundation, Inc. # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add `dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/ \1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/ / G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/install-sh000077500000000000000000000332561273231111400267760ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # 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 # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/ltmain.sh000066400000000000000000010520401273231111400266030ustar00rootroot00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/build-aux/missing000077500000000000000000000241521273231111400263640ustar00rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/cmake/000077500000000000000000000000001273231111400241475ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/cmake/internal_utils.cmake000066400000000000000000000225141273231111400302110ustar00rootroot00000000000000# Defines functions and macros useful for building Google Test and # Google Mock. # # Note: # # - This file will be run twice when building Google Mock (once via # Google Test's CMakeLists.txt, and once via Google Mock's). # Therefore it shouldn't have any side effects other than defining # the functions and macros. # # - The functions/macros defined in this file may depend on Google # Test and Google Mock's option() definitions, and thus must be # called *after* the options have been defined. # Tweaks CMake's default compiler/linker settings to suit Google Test's needs. # # This must be a macro(), as inside a function string() can only # update variables in the function scope. macro(fix_default_compiler_settings_) if (MSVC) # For MSVC, CMake sets certain flags to defaults we want to override. # This replacement code is taken from sample in the CMake Wiki at # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) # When Google Test is built as a shared library, it should also use # shared runtime libraries. Otherwise, it may end up with multiple # copies of runtime library data in different modules, resulting in # hard-to-find crashes. When it is built as a static library, it is # preferable to use CRT as static libraries, as we don't have to rely # on CRT DLLs being available. CMake always defaults to using shared # CRT libraries, so we override that default here. string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") endif() # We prefer more strict warning checking for building Google Test. # Replaces /W3 with /W4 in defaults. string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") endforeach() endif() endmacro() # Defines the compiler/linker flags used to build Google Test and # Google Mock. You can tweak these definitions to suit your need. A # variable's value is empty before it's explicitly assigned to. macro(config_compiler_and_linker) if (NOT gtest_disable_pthreads) # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. find_package(Threads) endif() fix_default_compiler_settings_() if (MSVC) # Newlines inside flags variables break CMake's NMake generator. # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") if (MSVC_VERSION LESS 1400) # Suppress spurious warnings MSVC 7.1 sometimes issues. # Forcing value to bool. set(cxx_base_flags "${cxx_base_flags} -wd4800") # Copy constructor and assignment operator could not be generated. set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512") # Compatibility warnings not applicable to Google Test. # Resolved overload was found by argument-dependent lookup. set(cxx_base_flags "${cxx_base_flags} -wd4675") endif() set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-GR-") elseif (CMAKE_COMPILER_IS_GNUCXX) set(cxx_base_flags "-Wall -Wshadow") set(cxx_exception_flags "-fexceptions") set(cxx_no_exception_flags "-fno-exceptions") # Until version 4.3.2, GCC doesn't define a macro to indicate # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI # explicitly. set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") set(cxx_strict_flags "-Wextra -Wno-unused-parameter -Wno-missing-field-initializers") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") set(cxx_exception_flags "-features=except") # Sun Pro doesn't provide macros to indicate whether exceptions and # RTTI are enabled, so we define GTEST_HAS_* explicitly. set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR CMAKE_CXX_COMPILER_ID STREQUAL "XL") # CMake 2.8 changes Visual Age's compiler ID to "XL". set(cxx_exception_flags "-qeh") set(cxx_no_exception_flags "-qnoeh") # Until version 9.0, Visual Age doesn't define a macro to indicate # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI # explicitly. set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP") set(cxx_base_flags "-AA -mt") set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1") set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0") # RTTI can not be disabled in HP aCC compiler. set(cxx_no_rtti_flags "") endif() if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") else() set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") endif() # For building gtest's own tests and samples. set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") set(cxx_no_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") set(cxx_default "${cxx_exception}") set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") # For building the gtest libraries. set(cxx_strict "${cxx_default} ${cxx_strict_flags}") endmacro() # Defines the gtest & gtest_main libraries. User tests should link # with one of them. function(cxx_library_with_type name type cxx_flags) # type can be either STATIC or SHARED to denote a static or shared library. # ARGN refers to additional arguments after 'cxx_flags'. add_library(${name} ${type} ${ARGN}) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") endif() if (CMAKE_USE_PTHREADS_INIT) target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) endif() endfunction() ######################################################################## # # Helper functions for creating build targets. function(cxx_shared_library name cxx_flags) cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) endfunction() function(cxx_library name cxx_flags) cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) endfunction() # cxx_executable_with_flags(name cxx_flags libs srcs...) # # creates a named C++ executable that depends on the given libraries and # is built from the given source files with the given compiler flags. function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) if (cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") endif() if (BUILD_SHARED_LIBS) set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") endif() # To support mixing linking in static and dynamic libraries, link each # library in with an extra call to target_link_libraries. foreach (lib "${libs}") target_link_libraries(${name} ${lib}) endforeach() endfunction() # cxx_executable(name dir lib srcs...) # # creates a named target that depends on the given libs and is built # from the given source files. dir/name.cc is implicitly included in # the source file list. function(cxx_executable name dir libs) cxx_executable_with_flags( ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) endfunction() # Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. find_package(PythonInterp) # cxx_test_with_flags(name cxx_flags libs srcs...) # # creates a named C++ test that depends on the given libs and is built # from the given source files with the given compiler flags. function(cxx_test_with_flags name cxx_flags libs) cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) add_test(${name} ${name}) endfunction() # cxx_test(name libs srcs...) # # creates a named test target that depends on the given libs and is # built from the given source files. Unlike cxx_test_with_flags, # test/name.cc is already implicitly included in the source file list. function(cxx_test name libs) cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" "test/${name}.cc" ${ARGN}) endfunction() # py_test(name) # # creates a Python test with the given name whose main module is in # test/name.py. It does nothing if Python is not installed. function(py_test name) # We are not supporting Python tests on Linux yet as they consider # all Linux environments to be google3 and try to use google3 features. if (PYTHONINTERP_FOUND) # ${CMAKE_BINARY_DIR} is known at configuration time, so we can # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known # only at ctest runtime (by calling ctest -c ), so # we have to escape $ to delay variable substitution here. add_test(${name} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) endif() endfunction() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/000077500000000000000000000000001273231111400246405ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest.cbproj000066400000000000000000000243661273231111400272020ustar00rootroot00000000000000 {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 3 4 5 6 7 8 0 1 2 9 10 11 12 14 13 15 16 17 18 Cfg_1 Cfg_2 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest.groupproj000066400000000000000000000037301273231111400277420ustar00rootroot00000000000000 {c1d923e0-6cba-4332-9b6f-3420acbf5091} Default.Personality mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest_all.cc000066400000000000000000000035111273231111400271250ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: Josh Kelley (joshkel@gmail.com) // // Google C++ Testing Framework (Google Test) // // C++Builder's IDE cannot build a static library from files with hyphens // in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 . // This file serves as a workaround. #include "src/gtest-all.cc" mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest_link.cc000066400000000000000000000037111273231111400273140ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: Josh Kelley (joshkel@gmail.com) // // Google C++ Testing Framework (Google Test) // // Links gtest.lib and gtest_main.lib into the current project in C++Builder. // This means that these libraries can't be renamed, but it's the only way to // ensure that Debug versus Release test builds are linked against the // appropriate Debug or Release build of the libraries. #pragma link "gtest.lib" #pragma link "gtest_main.lib" mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest_main.cbproj000066400000000000000000000206041273231111400301750ustar00rootroot00000000000000 {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 0 Cfg_1 Cfg_2 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/codegear/gtest_unittest.cbproj000066400000000000000000000207631273231111400311360ustar00rootroot00000000000000 {eea63393-5ac5-4b9c-8909-d75fef2daa41} Release true true true Base true true Base exe true NO_STRICT JPHNE true ..\test true CppConsoleApplication true true rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;.. $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test true false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppConsoleApplication FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test2NO_STRICTSTRICT 0 1 Cfg_1 Cfg_2 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/configure000077500000000000000000021163601273231111400250070ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for Google C++ Testing Framework 1.7.0. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: googletestframework@googlegroups.com about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Google C++ Testing Framework' PACKAGE_TARNAME='gtest' PACKAGE_VERSION='1.7.0' PACKAGE_STRING='Google C++ Testing Framework 1.7.0' PACKAGE_BUGREPORT='googletestframework@googlegroups.com' PACKAGE_URL='' ac_unique_file="./LICENSE" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS HAVE_PTHREADS_FALSE HAVE_PTHREADS_TRUE PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC acx_pthread_config HAVE_PYTHON_FALSE HAVE_PYTHON_TRUE PYTHON CXXCPP CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock with_pthreads ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP CXXCPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Google C++ Testing Framework 1.7.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/gtest] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Google C++ Testing Framework 1.7.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-pthreads use pthreads (default is yes) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Google C++ Testing Framework configure 1.7.0 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Google C++ Testing Framework $as_me 1.7.0, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Provide various options to initialize the Autoconf and configure processes. ac_aux_dir= for ac_dir in build-aux "$srcdir"/build-aux; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_headers="$ac_config_headers build-aux/config.h" ac_config_files="$ac_config_files Makefile" ac_config_files="$ac_config_files scripts/gtest-config" # Initialize Automake with various options. We require at least v1.9, prevent # pedantic complaints about package files, and enable various distribution # targets. am__api_version='1.11' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='gtest' VERSION='1.7.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Check for programs used in building Google Test. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu CC="$lt_save_CC" if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu else _lt_caught_CXX_error=yes fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds reload_flag_CXX=$reload_flag reload_cmds_CXX=$reload_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec_CXX='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty # executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' fi archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared # libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_CXX=' ' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=yes file_list_spec_CXX='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' enable_shared_with_static_runtimes_CXX=yes # Don't use ranlib old_postinstall_cmds_CXX='chmod 644 $oldlib' postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec_CXX='' fi link_all_deplibs_CXX=yes allow_undefined_flag_CXX="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" if test "$lt_cv_apple_cc_single_mod" != "yes"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; haiku*) archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs_CXX=yes ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5].* | *pgcpp\ [1-5].*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ '"$old_archive_cmds_CXX" reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ '"$reload_cmds_CXX" ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) # IBM XL 8.0, 9.0 on PPC and BlueGene lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' ;; esac ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs_CXX=no ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc_CXX=no else lt_cv_archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 $as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink || test "$inherit_rpath_CXX" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_config_commands="$ac_config_commands libtool" # Only expand once: # TODO(chandlerc@google.com): Currently we aren't running the Python tests # against the interpreter detected by AM_PATH_PYTHON, and so we condition # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" # hashbang. PYTHON= # We *do not* allow the user to specify a python interpreter # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PYTHON" && ac_cv_path_PYTHON=":" ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$PYTHON" != ":"; then : prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.3'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : : else PYTHON=":" fi fi if test "$PYTHON" != ":"; then HAVE_PYTHON_TRUE= HAVE_PYTHON_FALSE='#' else HAVE_PYTHON_TRUE='#' HAVE_PYTHON_FALSE= fi # Configure pthreads. # Check whether --with-pthreads was given. if test "${with_pthreads+set}" = set; then : withval=$with_pthreads; with_pthreads=$withval else with_pthreads=check fi have_pthreads=no if test "x$with_pthreads" != "xno"; then : ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 $as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_join (); int main () { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 $as_echo_n "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_acx_pthread_config+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$acx_pthread_config"; then ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_acx_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" fi fi acx_pthread_config=$ac_cv_prog_acx_pthread_config if test -n "$acx_pthread_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 $as_echo "$acx_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 $as_echo_n "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : acx_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 $as_echo "$acx_pthread_ok" >&6; } if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int attr=$attr; return attr; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : attr_name=$attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 $as_echo "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then cat >>confdefs.h <<_ACEOF #define PTHREAD_CREATE_JOINABLE $attr_name _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 $as_echo_n "checking if more special flags are required for pthreads... " >&6; } flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 $as_echo "${flag}" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then for ac_prog in xlc_r cc_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PTHREAD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_PTHREAD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 $as_echo "$PTHREAD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to check for GCC pthread/shared inconsistencies" >&5 $as_echo_n "checking whether to check for GCC pthread/shared inconsistencies... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is sufficient with -shared" >&5 $as_echo_n "checking whether -pthread is sufficient with -shared... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread fixes that" >&5 $as_echo_n "checking whether -lpthread fixes that... " >&6; } LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc_r fixes that" >&5 $as_echo_n "checking whether -lc_r fixes that... " >&6; } LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : done=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "x$done" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test x"$done" = xno; then # OK, we have run out of ideas { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries" >&5 $as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries" >&2;} # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else acx_pthread_ok=no if test "x$with_pthreads" != "xcheck"; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--with-pthreads was specified, but unable to be used See \`config.log' for more details" "$LINENO" 5; } fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu have_pthreads="$acx_pthread_ok" fi if test "x$have_pthreads" = "xyes"; then HAVE_PTHREADS_TRUE= HAVE_PTHREADS_FALSE='#' else HAVE_PTHREADS_TRUE='#' HAVE_PTHREADS_FALSE= fi # TODO(chandlerc@google.com) Check for the necessary system headers. # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. # Output the generated files. No further autoconf macros may be used. cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PTHREADS_TRUE}" && test -z "${HAVE_PTHREADS_FALSE}"; then as_fn_error $? "conditional \"HAVE_PTHREADS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Google C++ Testing Framework $as_me 1.7.0, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Google C++ Testing Framework config.status 1.7.0 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ reload_flag_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_separator_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ reload_cmds_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX \ postlink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "build-aux/config.h") CONFIG_HEADERS="$CONFIG_HEADERS build-aux/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "scripts/gtest-config") CONFIG_FILES="$CONFIG_FILES scripts/gtest-config" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "scripts/gtest-config":F) chmod +x scripts/gtest-config ;; "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # How to create reloadable object files. reload_flag=$lt_reload_flag_CXX reload_cmds=$lt_reload_cmds_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/configure.ac000066400000000000000000000050161273231111400253570ustar00rootroot00000000000000m4_include(m4/acx_pthread.m4) # At this point, the Xcode project assumes the version string will be three # integers separated by periods and surrounded by square brackets (e.g. # "[1.0.1]"). It also asumes that there won't be any closing parenthesis # between "AC_INIT(" and the closing ")" including comments and strings. AC_INIT([Google C++ Testing Framework], [1.7.0], [googletestframework@googlegroups.com], [gtest]) # Provide various options to initialize the Autoconf and configure processes. AC_PREREQ([2.59]) AC_CONFIG_SRCDIR([./LICENSE]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([build-aux/config.h]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config]) # Initialize Automake with various options. We require at least v1.9, prevent # pedantic complaints about package files, and enable various distribution # targets. AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) # Check for programs used in building Google Test. AC_PROG_CC AC_PROG_CXX AC_LANG([C++]) AC_PROG_LIBTOOL # TODO(chandlerc@google.com): Currently we aren't running the Python tests # against the interpreter detected by AM_PATH_PYTHON, and so we condition # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" # hashbang. PYTHON= # We *do not* allow the user to specify a python interpreter AC_PATH_PROG([PYTHON],[python],[:]) AS_IF([test "$PYTHON" != ":"], [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) # Configure pthreads. AC_ARG_WITH([pthreads], [AS_HELP_STRING([--with-pthreads], [use pthreads (default is yes)])], [with_pthreads=$withval], [with_pthreads=check]) have_pthreads=no AS_IF([test "x$with_pthreads" != "xno"], [ACX_PTHREAD( [], [AS_IF([test "x$with_pthreads" != "xcheck"], [AC_MSG_FAILURE( [--with-pthreads was specified, but unable to be used])])]) have_pthreads="$acx_pthread_ok"]) AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" = "xyes"]) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_LIBS) # TODO(chandlerc@google.com) Check for the necessary system headers. # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. # Output the generated files. No further autoconf macros may be used. AC_OUTPUT mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/fused-src/000077500000000000000000000000001273231111400247625ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/fused-src/gtest/000077500000000000000000000000001273231111400261105ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/fused-src/gtest/gtest-all.cc000066400000000000000000012640701273231111400303250ustar00rootroot00000000000000// 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. // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. virtual ~ScopedFakeTestPartResultReporter(); // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. virtual void ReportTestPartResult(const TestPartResult& result); private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const 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_ #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const std::string &test_case_name, const std::string &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual string CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test case, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. GTEST_API_ std::string GetLastErrnoDescription(); # if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; # endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. # if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); # else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); # endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } virtual ~SocketWriter() { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. virtual void Send(const string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const int len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != len) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const string host_name_; const string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static string UrlEncode(const char* str); StreamingListener(const string& host, const string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal static const char* GetDefaultFilter() { return kUniversalFilter; } GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. GTEST_API_ int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. std::string g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter( const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const std::string &test_name) { const std::string& full_name = test_case_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); std::string positive; std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == NULL) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const string& substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return ""; } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; # ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); # pragma warning(pop) // Restores the warning state. # else _ftime64(&now); # endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." #endif } // Utilities // class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& Message::operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new ::std::string(*other.message_) : static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; # else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } # endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, Mac OS X and Cygwin don't define wcscasecmp. // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Returns true iff str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } bool ValidateTestPropertyName(const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, ""); // No stack trace, either. } } // namespace internal // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const TestInfo* const first_test_info = test_case->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. const TestInfo* const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(NULL, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } private: std::string name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test only if the test object was created and its // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. int TestCase::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestCase::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // a_type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static std::string FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // Text printed in Google Test's text output and --gunit_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { printf("%s = %s", kValueParamLabel, value_param); } } } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == NULL) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_info.test_case_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(::std::ostream* stream, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } break; } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms/1000.0; return ss.str(); } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { // Using non-reentrant version as localtime_r is not portable. time_t seconds = static_cast(ms / 1000); #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function or variable may be unsafe). const struct tm* const time_struct = localtime(&seconds); // NOLINT # pragma warning(pop) // Restores the warning state again. #else const struct tm* const time_struct = localtime(&seconds); // NOLINT #endif if (time_struct == NULL) return ""; // Invalid ms value // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct->tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct->tm_mday) + "T" + String::FormatIntWidth2(time_struct->tm_hour) + ":" + String::FormatIntWidth2(time_struct->tm_min) + ":" + String::FormatIntWidth2(time_struct->tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; *stream << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, const TestCase& test_case) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { if (unit_test.GetTestCase(i)->reportable_test_count() > 0) PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. string StreamingListener::UrlEncode(const char* str) { string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = NULL; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, int /* skip_count */) GTEST_LOCK_EXCLUDED_(mutex_) { return ""; } void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath) { // If a path to the premature-exit file is specified... if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { remove(premature_exit_filepath_); } } private: const char* const premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: Symbian doesn't implement abort() well, and some debuggers // don't correctly trap abort(). *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); # endif // !GTEST_OS_WINDOWS_MOBILE # if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); # endif # if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } #endif // GTEST_HAS_SEH return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), # pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test case's ad_hoc_test_result when invoke // from SetUpTestCase/TearDownTestCase, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != NULL) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_case_ != NULL) { xml_element = "testsuite"; test_result = &(current_test_case_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", target.c_str()); fflush(stdout); } } } #endif // GTEST_CAN_STREAM_RESULTS_ // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const std::string& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: std::string name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(test_case_name, kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return false; } // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return true; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const std::string &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const std::string test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != NULL) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.", test_case->name()); if (test_case->type_param() != NULL) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != NULL) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? &(current_test_info_->result_) : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" #endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX #endif // GTEST_HAS_DEATH_TEST // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "the '|' characters. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. static bool g_in_fast_death_test_child = false; // 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. bool InDeathTestChild() { # if GTEST_OS_WINDOWS // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { # if GTEST_OS_WINDOWS return exit_status == exit_code_; # else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; # endif // GTEST_OS_WINDOWS } # if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; # else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } # ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } # endif # endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } # if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } # endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. // TODO(vladl@google.com): Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); posix::Abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. # define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestThrew: set_outcome(THREW); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, THREW, or RETURNED. The death test // fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const std::string error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } # if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } # else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); return args; } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; # if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } # else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC # if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } # else const bool use_fork = true; # endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, NULL)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } # endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } # if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } # endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; # if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); # else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: keith.ray@gmail.com (Keith Ray) #include #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) # define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; # else const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { 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_.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 // 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 #include #include #include #if GTEST_OS_WINDOWS_MOBILE # include // For TerminateProcess() #elif GTEST_OS_WINDOWS # include # include #else # include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include #endif // GTEST_OS_QNX // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(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(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(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 , 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(-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(pattern_)); free(const_cast(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(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(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 g_argvs; static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& 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(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 // 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::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 #include #include // NOLINT #include 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 static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(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(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(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(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(static_cast(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 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(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(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(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(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(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 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 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_(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_(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 // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // The Google C++ Testing Framework (Google Test) // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. 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(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (IsSpace(*str)) str++; return str; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef ::std::set::const_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 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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/fused-src/gtest/gtest.h000066400000000000000000031261431273231111400274210ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test // is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // IteratorTraits - partial implementation of std::iterator_traits, which // is not available in libCstd when compiled with Sun C++. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like // platforms, or a reduced regular exception syntax on // other platforms, including Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. # define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ # define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(__MINGW__) || defined(__MINGW32__) # define GTEST_OS_WINDOWS_MINGW 1 # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # if TARGET_IPHONE_SIMULATOR # define GTEST_OS_IOS_SIMULATOR 1 # endif # endif #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #elif defined __MVS__ # define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) # define GTEST_OS_SOLARIS 1 #elif defined(_AIX) # define GTEST_OS_AIX 1 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. # if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else # define GTEST_LANG_CXX11 0 # endif #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if !GTEST_OS_WINDOWS // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #elif !GTEST_OS_WINDOWS_MOBILE # include # include #endif #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_HAS_POSIX_RE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # define GTEST_HAS_EXCEPTIONS 1 # else // For other compilers, we assume exceptions are disabled to be // conservative. # define GTEST_HAS_EXCEPTIONS 0 # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. # error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). # define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. # ifdef _MSC_VER # ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # ifdef __RTTI_ALL__ # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif # else // For all other compilers, we assume RTTI is enabled. # define GTEST_HAS_RTTI 1 # endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ || GTEST_OS_QNX) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 # endif #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, libstdc++ 4.0.0+ and // MSVC 2010 are the only mainstream standard libraries that come // with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler // pretends to be GCC by defining __GNUC__ and friends, but cannot // compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 // tuple in a 323 MB Feature Pack download, which we cannot assume the // user has. QNX's QCC compiler is a modified GCC but it doesn't // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif // C++11 specifies that provides std::tuple. Use that if gtest is used // in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 // can build with clang but need to use gcc4.2's libstdc++). # if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) # define GTEST_ENV_HAS_STD_TUPLE_ 1 # endif # if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ # define GTEST_USE_OWN_TR1_TUPLE 0 # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE # if GTEST_USE_OWN_TR1_TUPLE // This file was GENERATED by command: // pump.py gtest-tuple.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) # define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else # define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than // ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. // This causes undefined behavior, but supported compilers react in // the way we intend. namespace std { namespace tr1 { using ::std::get; using ::std::make_tuple; using ::std::tuple; using ::std::tuple_element; using ::std::tuple_size; } } # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. # ifdef BOOST_HAS_TR1_TUPLE # undef BOOST_HAS_TR1_TUPLE # endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 # else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. # include // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() is only available on ARM starting with Gingerbread. # if defined(__arm__) && __ANDROID_API__ >= 9 # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 # endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else # define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &);\ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. # define GTEST_HAS_SEH 1 # else // Assume no SEH. # define GTEST_HAS_SEH 0 # endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif #endif // _MSC_VER #ifndef GTEST_API_ # define GTEST_API_ #endif #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 #endif namespace testing { class Message; namespace internal { // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. template struct CompileAssert { }; #define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ // Implementation details of GTEST_COMPILE_ASSERT_: // // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // GTEST_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. // StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. // // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; #if GTEST_HAS_GLOBAL_STRING typedef ::string string; #else typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING typedef ::wstring wstring; #elif GTEST_HAS_STD_WSTRING typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be // used where std::string is not available. TODO(wan@google.com): change to // std::string. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // 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); // 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. GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. if (false) { const To to = NULL; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(f); } // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST const ::std::vector& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void (*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // Forward-declares a static mutex. # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, // instead relying on default initialization for the unspecified fields. In // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. # define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else # define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) # define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { typedef T value_type; }; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; # ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } # else inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } # endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). # pragma warning(push) # pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't // complain about _snprintf. # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) // Thread annotations #define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) #define GTEST_LOCK_EXCLUDED_(locks) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #if GTEST_OS_LINUX # include # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include // 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 // 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 inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template 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 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 inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template 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 std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file 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 . // 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 #endif #include #include 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_ // 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 . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const 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_.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_ // This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar class ProtocolMessage; namespace proto2 { class Message; } namespace testing { // Forward declarations. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. template ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. GTEST_API_ extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char (&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_IS_NULL_LITERAL_(x) false #else # define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for // errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; #endif // GTEST_HAS_EXCEPTIONS // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? str : std::string(str, comma); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + StreamableToString(index)).c_str(), GetPrefixUntilComma(test_names).c_str(), GetTypeName().c_str(), NULL, // No value parameter. GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // Removes the reference from a type if it is a reference type, // otherwise leaves it unchanged. This is the same as // tr1::remove_reference, which is not widely available yet. template struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. #define GTEST_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves // it unchanged. This is the same as tr1::remove_const, which is not // widely available yet. template struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // definition to fail to remove the const in 'const int[3]' and 'const // char[3][4]'. The following specialization works around the bug. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #if defined(_MSC_VER) && _MSC_VER < 1400 // This is the only specialization that allows VC++ 7.1 to remove const in // 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC // and thus needs to be conditionally compiled. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #endif // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GTEST_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) // Adds reference to a type if it is not a reference type, // otherwise leaves it unchanged. This is the same as // tr1::add_reference, which is not widely available yet. template struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. #define GTEST_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, // it transforms // // char ==> const char& // const char ==> const char& // char& ==> const char& // const char& ==> const char& // // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template class ImplicitlyConvertible { private: // We need the following helper functions only for their types. // They have no implementations. // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. static From MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be // implicitly converted to type To; otherwise it will pick the // second version. // // The first version returns a value of size 1, and the second // version returns a value of size 2. Therefore, by checking the // size of Helper(x), which can be done at compile time, we can tell // which version of Helper() is used, and hence whether x can be // implicitly converted to type To. static char Helper(To); static char (&Helper(...))[2]; // NOLINT // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the // warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4244) // Temporarily disables warning 4244. static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; # pragma warning(pop) // Restores the warning state. #elif defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; #endif // _MSV_VER }; template const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // Note that we look for both C::iterator and C::const_iterator. The // reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add // "typename EnableIf::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { typedef void type; }; // NOLINT // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. enum RelationToSource { kReference, // The NativeArray references the native array. kCopy // The NativeArray makes a copy of the native array and // owns the copy. }; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. NativeArray(const Element* array, size_t count, RelationToSource relation) { Init(array, count, relation); } // Copy constructor. NativeArray(const NativeArray& rhs) { Init(rhs.array_, rhs.size_, rhs.relation_to_source_); } ~NativeArray() { // Ensures that the user doesn't instantiate NativeArray with a // const or reference type. static_cast(StaticAssertTypeEqHelper()); if (relation_to_source_ == kCopy) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: // Initializes this object; makes a copy of the input array if // 'relation' is kCopy. void Init(const Element* array, size_t a_size, RelationToSource relation) { if (relation == kReference) { array_ = array; } else { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; } size_ = a_size; relation_to_source_ = relation; } const Element* array_; size_t size_; RelationToSource relation_to_source_; GTEST_DISALLOW_ASSIGN_(NativeArray); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::ConstCharPtr gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg.value) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws.") #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ };\ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, NULL, NULL, \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #include 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_ 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 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_ // This file was GENERATED by command: // pump.py gtest-param-test.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #if !GTEST_OS_SYMBIAN # include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2003 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: Dan Egnor (egnor@google.com) // // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. // // Used properly, this deletes the object when the last reference goes away. // There are several caveats: // - Like all reference counting schemes, cycles lead to leaks. // - Each smart pointer is actually two pointers (8 bytes instead of 4). // - Every time a pointer is assigned, the entire list of pointers to that // object is traversed. This class is therefore NOT SUITABLE when there // will often be more than two or three pointers to a particular object. // - References are only tracked as long as linked_ptr<> objects are copied. // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS // will happen (double deletion). // // A good use of this class is storing object references in STL containers. // You can safely put linked_ptr<> in a vector<>. // Other uses may not be as good. // // Note: If you use an incomplete type with linked_ptr<>, the class // *containing* linked_ptr<> must have a constructor and destructor (even // if they do nothing!). // // Bill Gibbons suggested we use something like this. // // Thread Safety: // Unlike other linked_ptr implementations, in this implementation // a linked_ptr object is thread-safe in the sense that: // - it's safe to copy linked_ptr objects concurrently, // - it's safe to copy *from* a linked_ptr and read its underlying // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #include #include 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(obj) vs linked_ptr(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. 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, linked_ptr, and // linked_ptr). 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 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 linked_ptr(linked_ptr 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 linked_ptr& operator=(linked_ptr 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 bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template 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 void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ // 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::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 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 // NOLINT #include #include #include #include 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::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 class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&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 class TypeWithoutFormatter { 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 class TypeWithoutFormatter { 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::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 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, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::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 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::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 class UniversalPrinter; template 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 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 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::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( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template 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::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 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(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::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(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_(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_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(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_(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 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 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 void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template void PrintTo(const ::std::pair& 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::Print(value.first, os); *os << ", "; UniversalPrinter::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 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 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 class UniversalPrinter { 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 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 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(&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 class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { 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 { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::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 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::Print(value, os); } #if GTEST_HAS_TR1_TUPLE typedef ::std::vector 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::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); *os << ", "; UniversalPrinter::type> ::Print(::std::tr1::get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(::std::tr1::get(t), &ss); strings->push_back(ss.str()); } }; // Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template 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 static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { UniversalPrinter::type>:: Print(::std::tr1::get<0>(t), os); } template 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 void PrintTupleTo(const T& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter< ::std::tr1::tuple_size::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 Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing #endif // GTEST_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 class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template 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* 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. 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::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::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template 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* 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; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* 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 > 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 class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& 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(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* 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 class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* 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& 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(&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(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* 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 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 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 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 TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(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 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(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(); } // 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* meta_factory) { tests_.push_back(linked_ptr(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 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 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::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* 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 > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > 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 ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* 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()) { // 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 >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(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 TestCaseInfoContainer; TestCaseInfoContainer test_case_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); }; } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ // This file was GENERATED by command: // pump.py gtest-param-util-generated.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(v50_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; # if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 # endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } # if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } # endif // GTEST_HAS_COMBINE # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Google C++ Testing Framework definitions useful in production code. #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST(MyClassTest, MyMethod); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, MyMethod) { // // Can call MyClass::MyMethod() here. // } #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include 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 array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); virtual ~HasNewFatalFailureHelper(); virtual void ReportTestPartResult(const TestPartResult& result); bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list 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 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 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 MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); #endif // 0 // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::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 \ class TestName : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::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) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestCase; class TestInfo; class UnitTest; // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == NULL) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const std::string& a_key, const std::string& a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::string value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class TestCase; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != NULL) return value_param_->c_str(); return NULL; } // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } // Returns true iff this test will appear in the XML report. bool is_reportable() const { // For now, the XML report includes all tests matching the filter. // In the future, we may trim tests that are excluded because of // sharding. return matches_filter_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_case_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_case_name_; // Test case name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a // type-parameterized test case. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestCase and TearDownTestCase. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Runs SetUpTestCase() for this TestCase. This wrapper is needed // for catching exceptions thrown from SetUpTestCase(). void RunSetUpTestCase() { (*set_up_tc_)(); } // Runs TearDownTestCase() for this TestCase. This wrapper is // needed for catching exceptions thrown from TearDownTestCase(). void RunTearDownTestCase() { (*tear_down_tc_)(); } // Returns true iff test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true iff test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true iff the test is disabled and will be reported in the XML // report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true iff test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true iff this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // Holds test properties recorded during execution of SetUpTestCase and // TearDownTestCase. TestResult ad_hoc_test_result_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::string& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_GLOBAL_STRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); #endif #if GTEST_HAS_GLOBAL_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); #endif #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal, like NULL, false, or 0. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. Secret* /* expected (NULL) */, T* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, <); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, >); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; ::std::stringstream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StringStreamToString(&expected_ss), StringStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; std::string const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that // uses a fixture whose parameter type is int. const ParamType& GetParam() const { GTEST_CHECK_(parameter_ != NULL) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL # define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED # define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is AUTOMATICALLY GENERATED on 10/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 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 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 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 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 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_ // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. # define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) # define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST # define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) } // namespace testing // Use this function in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } #endif // GTEST_INCLUDE_GTEST_GTEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/fused-src/gtest/gtest_main.cc000066400000000000000000000033451273231111400305560ustar00rootroot00000000000000// 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 #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(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/000077500000000000000000000000001273231111400245125ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/000077500000000000000000000000001273231111400256405ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-death-test.h000066400000000000000000000264031273231111400312040ustar00rootroot00000000000000// 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 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-message.h000066400000000000000000000217421273231111400305670ustar00rootroot00000000000000// 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 #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 inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template 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 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 inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template 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 std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-param-test.h000066400000000000000000002241301273231111400312140ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gtest-param-test.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #include "gtest/internal/gtest-port.h" #if !GTEST_OS_SYMBIAN # include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } # if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } # endif // GTEST_HAS_COMBINE # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-param-test.h.pump000066400000000000000000000445541273231111400322060ustar00rootroot00000000000000$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of Values arguments we want to support. $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #include "gtest/internal/gtest-port.h" #if !GTEST_OS_SYMBIAN # include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to $n parameters. // $range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) { return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]); } ]] // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } # if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to $maxtuple arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // $range i 2..maxtuple $for i [[ $range j 1..i template <$for j, [[typename Generator$j]]> internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( $for j, [[const Generator$j& g$j]]) { return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>( $for j, [[g$j]]); } ]] # endif // GTEST_HAS_COMBINE # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-printers.h000066400000000000000000000755711273231111400310220ustar00rootroot00000000000000// 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::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 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 // NOLINT #include #include #include #include #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::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 class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&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 class TypeWithoutFormatter { 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 class TypeWithoutFormatter { 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::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 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, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::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 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::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 class UniversalPrinter; template 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 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 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::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( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template 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::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 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(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::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(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_(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_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(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_(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 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 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 void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template void PrintTo(const ::std::pair& 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::Print(value.first, os); *os << ", "; UniversalPrinter::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 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 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 class UniversalPrinter { 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 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 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(&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 class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { 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 { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::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 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::Print(value, os); } #if GTEST_HAS_TR1_TUPLE typedef ::std::vector 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::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); *os << ", "; UniversalPrinter::type> ::Print(::std::tr1::get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(::std::tr1::get(t), &ss); strings->push_back(ss.str()); } }; // Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template 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 static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { UniversalPrinter::type>:: Print(::std::tr1::get<0>(t), os); } template 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 void PrintTupleTo(const T& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter< ::std::tr1::tuple_size::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 Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-spi.h000066400000000000000000000233401273231111400277320ustar00rootroot00000000000000// 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-test-part.h000066400000000000000000000145551273231111400310720ustar00rootroot00000000000000// 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 #include #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 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest-typed-test.h000066400000000000000000000240021273231111400312350ustar00rootroot00000000000000// 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 class FooTest : public testing::Test { public: ... typedef std::list 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 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 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 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) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::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 \ class TestName : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::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) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest.h000066400000000000000000002545621273231111400271550ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" #include "gtest/gtest_prod.h" #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestCase; class TestInfo; class UnitTest; // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == NULL) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const std::string& a_key, const std::string& a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::string value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class TestCase; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != NULL) return value_param_->c_str(); return NULL; } // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } // Returns true iff this test will appear in the XML report. bool is_reportable() const { // For now, the XML report includes all tests matching the filter. // In the future, we may trim tests that are excluded because of // sharding. return matches_filter_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_case_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_case_name_; // Test case name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a // type-parameterized test case. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestCase and TearDownTestCase. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Runs SetUpTestCase() for this TestCase. This wrapper is needed // for catching exceptions thrown from SetUpTestCase(). void RunSetUpTestCase() { (*set_up_tc_)(); } // Runs TearDownTestCase() for this TestCase. This wrapper is // needed for catching exceptions thrown from TearDownTestCase(). void RunTearDownTestCase() { (*tear_down_tc_)(); } // Returns true iff test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true iff test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true iff the test is disabled and will be reported in the XML // report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true iff test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true iff this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // Holds test properties recorded during execution of SetUpTestCase and // TearDownTestCase. TestResult ad_hoc_test_result_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::string& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_GLOBAL_STRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); #endif #if GTEST_HAS_GLOBAL_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); #endif #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal, like NULL, false, or 0. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. Secret* /* expected (NULL) */, T* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, <); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, >); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; ::std::stringstream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StringStreamToString(&expected_ss), StringStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; std::string const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that // uses a fixture whose parameter type is int. const ParamType& GetParam() const { GTEST_CHECK_(parameter_ != NULL) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL # define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED # define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. #include "gtest/gtest_pred_impl.h" // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. # define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) # define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST # define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) } // namespace testing // Use this function in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } #endif // GTEST_INCLUDE_GTEST_GTEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest_pred_impl.h000066400000000000000000000354511273231111400312020ustar00rootroot00000000000000// 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 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 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 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 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 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/gtest_prod.h000066400000000000000000000044241273231111400301670ustar00rootroot00000000000000// 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/000077500000000000000000000000001273231111400274545ustar00rootroot00000000000000gtest-death-test-internal.h000066400000000000000000000321651273231111400345550ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal// 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 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-filepath.h000066400000000000000000000226031273231111400325500ustar00rootroot00000000000000// 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 . // 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_.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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-internal.h000066400000000000000000001261611273231111400325740ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #include "gtest/internal/gtest-port.h" #if GTEST_OS_LINUX # include # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar class ProtocolMessage; namespace proto2 { class Message; } namespace testing { // Forward declarations. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. template ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. GTEST_API_ extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char (&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_IS_NULL_LITERAL_(x) false #else # define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for // errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; #endif // GTEST_HAS_EXCEPTIONS // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? str : std::string(str, comma); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + StreamableToString(index)).c_str(), GetPrefixUntilComma(test_names).c_str(), GetTypeName().c_str(), NULL, // No value parameter. GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // Removes the reference from a type if it is a reference type, // otherwise leaves it unchanged. This is the same as // tr1::remove_reference, which is not widely available yet. template struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. #define GTEST_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves // it unchanged. This is the same as tr1::remove_const, which is not // widely available yet. template struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // definition to fail to remove the const in 'const int[3]' and 'const // char[3][4]'. The following specialization works around the bug. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #if defined(_MSC_VER) && _MSC_VER < 1400 // This is the only specialization that allows VC++ 7.1 to remove const in // 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC // and thus needs to be conditionally compiled. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #endif // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GTEST_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) // Adds reference to a type if it is not a reference type, // otherwise leaves it unchanged. This is the same as // tr1::add_reference, which is not widely available yet. template struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. #define GTEST_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, // it transforms // // char ==> const char& // const char ==> const char& // char& ==> const char& // const char& ==> const char& // // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template class ImplicitlyConvertible { private: // We need the following helper functions only for their types. // They have no implementations. // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. static From MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be // implicitly converted to type To; otherwise it will pick the // second version. // // The first version returns a value of size 1, and the second // version returns a value of size 2. Therefore, by checking the // size of Helper(x), which can be done at compile time, we can tell // which version of Helper() is used, and hence whether x can be // implicitly converted to type To. static char Helper(To); static char (&Helper(...))[2]; // NOLINT // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the // warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4244) // Temporarily disables warning 4244. static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; # pragma warning(pop) // Restores the warning state. #elif defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; #endif // _MSV_VER }; template const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // Note that we look for both C::iterator and C::const_iterator. The // reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add // "typename EnableIf::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { typedef void type; }; // NOLINT // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. enum RelationToSource { kReference, // The NativeArray references the native array. kCopy // The NativeArray makes a copy of the native array and // owns the copy. }; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. NativeArray(const Element* array, size_t count, RelationToSource relation) { Init(array, count, relation); } // Copy constructor. NativeArray(const NativeArray& rhs) { Init(rhs.array_, rhs.size_, rhs.relation_to_source_); } ~NativeArray() { // Ensures that the user doesn't instantiate NativeArray with a // const or reference type. static_cast(StaticAssertTypeEqHelper()); if (relation_to_source_ == kCopy) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: // Initializes this object; makes a copy of the input array if // 'relation' is kCopy. void Init(const Element* array, size_t a_size, RelationToSource relation) { if (relation == kReference) { array_ = array; } else { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; } size_ = a_size; relation_to_source_ = relation; } const Element* array_; size_t size_; RelationToSource relation_to_source_; GTEST_DISALLOW_ASSIGN_(NativeArray); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::ConstCharPtr gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg.value) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws.") #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ };\ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, NULL, NULL, \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h000066400000000000000000000176451273231111400331210ustar00rootroot00000000000000// 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 #include #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(obj) vs linked_ptr(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. 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, linked_ptr, and // linked_ptr). 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 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 linked_ptr(linked_ptr 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 linked_ptr& operator=(linked_ptr 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 bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template 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 void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ gtest-param-util-generated.h000066400000000000000000005672601273231111400347210ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal// This file was GENERATED by command: // pump.py gtest-param-util-generated.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(v50_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; # if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 # endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ gtest-param-util-generated.h.pump000066400000000000000000000223101273231111400356570ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of Values arguments we want to support. $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most $n arguments in Values, // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at $maxtuple. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; $range i 2..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { const T array[] = {$for j, [[static_cast(v$(j)_)]]}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray$i& other); $for j [[ const T$j v$(j)_; ]] }; ]] # if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // $range i 2..maxtuple $for i [[ $range j 1..i $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { public: typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} virtual ~CartesianProductGenerator$i() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); } virtual ParamIteratorInterface* End() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, $for j, [[ const ParamGenerator& g$j, const typename ParamGenerator::iterator& current$(j)]]) : base_(base), $for j, [[ begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j) ]] { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current$(i)_; $for k [[ if (current$(i+2-k)_ == end$(i+2-k)_) { current$(i+2-k)_ = begin$(i+2-k)_; ++current$(i+2-k-1)_; } ]] ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ($for j && [[ current$(j)_ == typed_other->current$(j)_ ]]); } private: Iterator(const Iterator& other) : base_(other.base_), $for j, [[ begin$(j)_(other.begin$(j)_), end$(j)_(other.end$(j)_), current$(j)_(other.current$(j)_) ]] { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType($for j, [[*current$(j)_]]); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return $for j || [[ current$(j)_ == end$(j)_ ]]; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. $for j [[ const typename ParamGenerator::iterator begin$(j)_; const typename ParamGenerator::iterator end$(j)_; typename ParamGenerator::iterator current$(j)_; ]] ParamType current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator$i& other); $for j [[ const ParamGenerator g$(j)_; ]] }; // class CartesianProductGenerator$i ]] // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // $range i 2..maxtuple $for i [[ $range j 1..i template <$for j, [[class Generator$j]]> class CartesianProductHolder$i { public: CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ static_cast >(g$(j)_) ]])); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder$i& other); $for j [[ const Generator$j g$(j)_; ]] }; // class CartesianProductHolder$i ]] # endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-param-util.h000066400000000000000000000571771273231111400330450ustar00rootroot00000000000000// 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 #include #include // 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 class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template 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* 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. 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::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::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template 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* 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; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* 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 > 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 class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& 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(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* 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 class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* 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& 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(&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(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* 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 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 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 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 TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(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 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(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(); } // 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* meta_factory) { tests_.push_back(linked_ptr(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 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 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::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* 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 > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > 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 ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* 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()) { // 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 >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(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 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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-port.h000066400000000000000000002062741273231111400317500ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test // is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // IteratorTraits - partial implementation of std::iterator_traits, which // is not available in libCstd when compiled with Sun C++. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like // platforms, or a reduced regular exception syntax on // other platforms, including Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. # define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ # define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(__MINGW__) || defined(__MINGW32__) # define GTEST_OS_WINDOWS_MINGW 1 # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # if TARGET_IPHONE_SIMULATOR # define GTEST_OS_IOS_SIMULATOR 1 # endif # endif #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #elif defined __MVS__ # define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) # define GTEST_OS_SOLARIS 1 #elif defined(_AIX) # define GTEST_OS_AIX 1 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. # if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else # define GTEST_LANG_CXX11 0 # endif #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if !GTEST_OS_WINDOWS // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #elif !GTEST_OS_WINDOWS_MOBILE # include # include #endif #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_HAS_POSIX_RE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # define GTEST_HAS_EXCEPTIONS 1 # else // For other compilers, we assume exceptions are disabled to be // conservative. # define GTEST_HAS_EXCEPTIONS 0 # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. # error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). # define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. # ifdef _MSC_VER # ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # ifdef __RTTI_ALL__ # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif # else // For all other compilers, we assume RTTI is enabled. # define GTEST_HAS_RTTI 1 # endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ || GTEST_OS_QNX) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 # endif #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, libstdc++ 4.0.0+ and // MSVC 2010 are the only mainstream standard libraries that come // with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler // pretends to be GCC by defining __GNUC__ and friends, but cannot // compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 // tuple in a 323 MB Feature Pack download, which we cannot assume the // user has. QNX's QCC compiler is a modified GCC but it doesn't // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif // C++11 specifies that provides std::tuple. Use that if gtest is used // in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 // can build with clang but need to use gcc4.2's libstdc++). # if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) # define GTEST_ENV_HAS_STD_TUPLE_ 1 # endif # if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ # define GTEST_USE_OWN_TR1_TUPLE 0 # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE # if GTEST_USE_OWN_TR1_TUPLE # include "gtest/internal/gtest-tuple.h" # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than // ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. // This causes undefined behavior, but supported compilers react in // the way we intend. namespace std { namespace tr1 { using ::std::get; using ::std::make_tuple; using ::std::tuple; using ::std::tuple_element; using ::std::tuple_size; } } # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. # ifdef BOOST_HAS_TR1_TUPLE # undef BOOST_HAS_TR1_TUPLE # endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 # else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. # include // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() is only available on ARM starting with Gingerbread. # if defined(__arm__) && __ANDROID_API__ >= 9 # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 # endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else # define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &);\ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. # define GTEST_HAS_SEH 1 # else // Assume no SEH. # define GTEST_HAS_SEH 0 # endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif #endif // _MSC_VER #ifndef GTEST_API_ # define GTEST_API_ #endif #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 #endif namespace testing { class Message; namespace internal { // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. template struct CompileAssert { }; #define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ // Implementation details of GTEST_COMPILE_ASSERT_: // // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // GTEST_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. // StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. // // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; #if GTEST_HAS_GLOBAL_STRING typedef ::string string; #else typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING typedef ::wstring wstring; #elif GTEST_HAS_STD_WSTRING typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be // used where std::string is not available. TODO(wan@google.com): change to // std::string. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // 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); // 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. GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. if (false) { const To to = NULL; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(f); } // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST const ::std::vector& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void (*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // Forward-declares a static mutex. # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, // instead relying on default initialization for the unspecified fields. In // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. # define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else # define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) # define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { typedef T value_type; }; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; # ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } # else inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } # endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). # pragma warning(push) # pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't // complain about _snprintf. # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) // Thread annotations #define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) #define GTEST_LOCK_EXCLUDED_(locks) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-string.h000066400000000000000000000154701273231111400322660ustar00rootroot00000000000000// 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 . // 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 #endif #include #include #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_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-tuple.h000066400000000000000000000670771273231111400321230ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gtest-tuple.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) # define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else # define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump000066400000000000000000000220121273231111400330570ustar00rootroot00000000000000$$ -*- mode: c++; -*- $var n = 10 $$ Maximum number of tuple fields we want to support. $$ This meta comment fixes auto-indentation in Emacs. }} // Copyright 2009 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) # define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else # define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif $range i 0..n-1 $range j 0..n $range k 1..n // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> $for k [[ $range m 0..k-1 $range m2 k..n-1 #define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]> ]] // GTEST_n_TYPENAMES_(T) declares a list of n typenames. $for j [[ $range m 0..j-1 #define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]] ]] // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template <$for i, [[typename T$i = void]]> class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; $for i [[ template struct TupleElement { typedef T$i type; }; ]] } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; $for k [[ $range m 0..k-1 template class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { public: template friend class gtest_internal::Get; tuple() : $for m, [[f$(m)_()]] {} explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]] $for m, [[f$(m)_(f$m)]] {} tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} template tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} $if k == 2 [[ template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} ]] tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { return CopyFrom(t); } $if k == 2 [[ template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } ]] GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) { $for m [[ f$(m)_ = t.f$(m)_; ]] return *this; } $for m [[ T$m f$(m)_; ]] }; ]] // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } $for k [[ $range m 0..k-1 template inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) { return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]); } ]] // 6.1.3.3 Tuple helper classes. template struct tuple_size; $for j [[ template struct tuple_size { static const int value = $j; }; ]] template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { $for i [[ template <> class Get<$i> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) Field(Tuple& t) { return t.f$(i)_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) ConstField(const Tuple& t) { return t.f$(i)_; } }; ]] } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(const GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std $for j [[ #undef GTEST_$(j)_TUPLE_ ]] $for j [[ #undef GTEST_$(j)_TYPENAMES_ ]] #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal/gtest-type-util.h000066400000000000000000005525021273231111400327160ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #include "gtest/internal/gtest-port.h" // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ gtest-type-util.h.pump000066400000000000000000000221451273231111400336120ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/include/gtest/internal$$ -*- mode: c++; -*- $var n = 50 $$ Maximum length of type lists we want to support. // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most $n types in a list, and at most $n // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #include "gtest/internal/gtest-port.h" // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; $range i 2..n $for i [[ $range j 1..i $range k 2..i template <$for j, [[typename T$j]]> struct Types$i { typedef T1 Head; typedef Types$(i-1)<$for k, [[T$k]]> Tail; }; ]] } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. $range i 1..n template <$for i, [[typename T$i = internal::None]]> struct Types { typedef internal::Types$n<$for i, [[T$i]]> type; }; template <> struct Types<$for i, [[internal::None]]> { typedef internal::Types0 type; }; $range i 1..n-1 $for i [[ $range j 1..i $range k i+1..n template <$for j, [[typename T$j]]> struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { typedef internal::Types$i<$for j, [[T$j]]> type; }; ]] namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; $range i 2..n $for i [[ $range j 1..i $range k 2..i template <$for j, [[GTEST_TEMPLATE_ T$j]]> struct Templates$i { typedef TemplateSel Head; typedef Templates$(i-1)<$for k, [[T$k]]> Tail; }; ]] // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. $range i 1..n template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> struct Templates { typedef Templates$n<$for i, [[T$i]]> type; }; template <> struct Templates<$for i, [[NoneT]]> { typedef Templates0 type; }; $range i 1..n-1 $for i [[ $range j 1..i $range k i+1..n template <$for j, [[GTEST_TEMPLATE_ T$j]]> struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { typedef Templates$i<$for j, [[T$j]]> type; }; ]] // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; $range i 1..n template <$for i, [[typename T$i]]> struct TypeList > { typedef typename Types<$for i, [[T$i]]>::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/000077500000000000000000000000001273231111400234075ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/acx_pthread.m4000066400000000000000000000317661273231111400261500ustar00rootroot00000000000000# This was retrieved from # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi # See also (perhaps for new versions?) # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi # # We've rewritten the inconsistency check code (from avahi), to work # more broadly. In particular, it no longer assumes ld accepts -zdefs. # This caused a restructing of the code, but the functionality has only # changed a little. dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) AC_TRY_LINK(,, , [done=yes]) if test "x$done" = xyes ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread fixes that]) LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lc_r fixes that]) LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi if test x"$done" = xno; then # OK, we have run out of ideas AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/gtest.m4000066400000000000000000000062211273231111400250000ustar00rootroot00000000000000dnl GTEST_LIB_CHECK([minimum version [, dnl action if found [,action if not found]]]) dnl dnl Check for the presence of the Google Test library, optionally at a minimum dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines dnl standard variables for substitution including GTEST_CPPFLAGS, dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines dnl GTEST_VERSION as the version of Google Test found. Finally, it provides dnl optional custom action slots in the event GTEST is found or not. AC_DEFUN([GTEST_LIB_CHECK], [ dnl Provide a flag to enable or disable Google Test usage. AC_ARG_ENABLE([gtest], [AS_HELP_STRING([--enable-gtest], [Enable tests using the Google C++ Testing Framework. (Default is enabled.)])], [], [enable_gtest=]) AC_ARG_VAR([GTEST_CONFIG], [The exact path of Google Test's 'gtest-config' script.]) AC_ARG_VAR([GTEST_CPPFLAGS], [C-like preprocessor flags for Google Test.]) AC_ARG_VAR([GTEST_CXXFLAGS], [C++ compile flags for Google Test.]) AC_ARG_VAR([GTEST_LDFLAGS], [Linker path and option flags for Google Test.]) AC_ARG_VAR([GTEST_LIBS], [Library linking flags for Google Test.]) AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_GTEST="no" AS_IF([test "x${enable_gtest}" != "xno"], [AC_MSG_CHECKING([for 'gtest-config']) AS_IF([test "x${enable_gtest}" != "xyes"], [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"]) AS_IF([test -x "${GTEST_CONFIG}"], [], [AC_MSG_RESULT([no]) AC_MSG_ERROR([dnl Unable to locate either a built or installed Google Test. The specific location '${enable_gtest}' was provided for a built or installed Google Test, but no 'gtest-config' script could be found at this location.]) ])], [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) AS_IF([test -x "${GTEST_CONFIG}"], [AC_MSG_RESULT([${GTEST_CONFIG}]) m4_ifval([$1], [_gtest_min_version="--min-version=$1" AC_MSG_CHECKING([for Google Test at least version >= $1])], [_gtest_min_version="--min-version=0" AC_MSG_CHECKING([for Google Test])]) AS_IF([${GTEST_CONFIG} ${_gtest_min_version}], [AC_MSG_RESULT([yes]) HAVE_GTEST='yes'], [AC_MSG_RESULT([no])])], [AC_MSG_RESULT([no])]) AS_IF([test "x${HAVE_GTEST}" = "xyes"], [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags` GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags` GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags` GTEST_LIBS=`${GTEST_CONFIG} --libs` GTEST_VERSION=`${GTEST_CONFIG} --version` AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])], [AS_IF([test "x${enable_gtest}" = "xyes"], [AC_MSG_ERROR([dnl Google Test was enabled, but no viable version could be found.]) ])])]) AC_SUBST([HAVE_GTEST]) AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"]) AS_IF([test "x$HAVE_GTEST" = "xyes"], [m4_ifval([$2], [$2])], [m4_ifval([$3], [$3])]) ]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/libtool.m4000066400000000000000000010604341273231111400253250ustar00rootroot00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/ltoptions.m4000066400000000000000000000300731273231111400257070ustar00rootroot00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/ltsugar.m4000066400000000000000000000104241273231111400253330ustar00rootroot00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/ltversion.m4000066400000000000000000000012621273231111400256770ustar00rootroot00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/m4/lt~obsolete.m4000066400000000000000000000137561273231111400262370ustar00rootroot00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/make/000077500000000000000000000000001273231111400240045ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/make/Makefile000066400000000000000000000053011273231111400254430ustar00rootroot00000000000000# A sample Makefile for building Google Test and using it in user # tests. Please tweak it to suit your environment and project. You # may want to move it to your project's root directory. # # SYNOPSIS: # # make [all] - makes everything. # make TARGET - makes the given target. # make clean - removes all files generated by make. # Please tweak the following variable definitions as needed by your # project, except GTEST_HEADERS, which you can use in your own targets # but shouldn't modify. # Points to the root of Google Test, relative to where this file is. # Remember to tweak this if you move this file. GTEST_DIR = .. # Where to find user code. USER_DIR = ../samples # Flags passed to the preprocessor. # Set Google Test's header directory as a system directory, such that # the compiler doesn't generate warnings in Google Test headers. CPPFLAGS += -isystem $(GTEST_DIR)/include # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread # All tests produced by this Makefile. Remember to add new tests you # created to the list. TESTS = sample1_unittest # All Google Test headers. Usually you shouldn't change this # definition. GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ $(GTEST_DIR)/include/gtest/internal/*.h # House-keeping build targets. all : $(TESTS) clean : rm -f $(TESTS) gtest.a gtest_main.a *.o # Builds gtest.a and gtest_main.a. # Usually you shouldn't tweak such internal variables, indicated by a # trailing _. GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) # For simplicity and to avoid depending on Google Test's # implementation details, the dependencies specified below are # conservative and not optimized. This is fine as Google Test # compiles fast and for ordinary users its source rarely changes. gtest-all.o : $(GTEST_SRCS_) $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(GTEST_DIR)/src/gtest-all.cc gtest_main.o : $(GTEST_SRCS_) $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(GTEST_DIR)/src/gtest_main.cc gtest.a : gtest-all.o $(AR) $(ARFLAGS) $@ $^ gtest_main.a : gtest-all.o gtest_main.o $(AR) $(ARFLAGS) $@ $^ # Builds a sample test. A test should link with either gtest.a or # gtest_main.a, depending on whether it defines its own main() # function. sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \ $(USER_DIR)/sample1.h $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc sample1_unittest : sample1.o sample1_unittest.o gtest_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/000077500000000000000000000000001273231111400240375ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest-md.sln000077500000000000000000000046301273231111400263070ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest-md.vcproj000077500000000000000000000064561273231111400270260ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest.sln000077500000000000000000000046001273231111400257060ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32 {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32 {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32 {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32 {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest.vcproj000077500000000000000000000064531273231111400264250ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_main-md.vcproj000077500000000000000000000066721273231111400300320ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_main.vcproj000077500000000000000000000066641273231111400274350ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_prod_test-md.vcproj000077500000000000000000000106431273231111400311020ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_prod_test.vcproj000077500000000000000000000106351273231111400305050ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_unittest-md.vcproj000077500000000000000000000076511273231111400307630ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/msvc/gtest_unittest.vcproj000077500000000000000000000076431273231111400303660ustar00rootroot00000000000000 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/000077500000000000000000000000001273231111400245335ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/prime_tables.h000066400000000000000000000077501273231111400273630ustar00rootroot00000000000000// 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) // Author: vladl@google.com (Vlad Losev) // This provides interface PrimeTable that determines whether a number is a // prime and determines a next prime number. This interface is used // in Google Test samples demonstrating use of parameterized tests. #ifndef GTEST_SAMPLES_PRIME_TABLES_H_ #define GTEST_SAMPLES_PRIME_TABLES_H_ #include // The prime table interface. class PrimeTable { public: virtual ~PrimeTable() {} // Returns true iff n is a prime number. virtual bool IsPrime(int n) const = 0; // Returns the smallest prime number greater than p; or returns -1 // if the next prime is beyond the capacity of the table. virtual int GetNextPrime(int p) const = 0; }; // Implementation #1 calculates the primes on-the-fly. class OnTheFlyPrimeTable : public PrimeTable { public: virtual bool IsPrime(int n) const { if (n <= 1) return false; for (int i = 2; i*i <= n; i++) { // n is divisible by an integer other than 1 and itself. if ((n % i) == 0) return false; } return true; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n > 0; n++) { if (IsPrime(n)) return n; } return -1; } }; // Implementation #2 pre-calculates the primes and stores the result // in an array. class PreCalculatedPrimeTable : public PrimeTable { public: // 'max' specifies the maximum number the prime table holds. explicit PreCalculatedPrimeTable(int max) : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) { CalculatePrimesUpTo(max); } virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; } virtual bool IsPrime(int n) const { return 0 <= n && n < is_prime_size_ && is_prime_[n]; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n < is_prime_size_; n++) { if (is_prime_[n]) return n; } return -1; } private: void CalculatePrimesUpTo(int max) { ::std::fill(is_prime_, is_prime_ + is_prime_size_, true); is_prime_[0] = is_prime_[1] = false; for (int i = 2; i <= max; i++) { if (!is_prime_[i]) continue; // Marks all multiples of i (except i itself) as non-prime. for (int j = 2*i; j <= max; j += i) { is_prime_[j] = false; } } } const int is_prime_size_; bool* const is_prime_; // Disables compiler warning "assignment operator could not be generated." void operator=(const PreCalculatedPrimeTable& rhs); }; #endif // GTEST_SAMPLES_PRIME_TABLES_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample1.cc000066400000000000000000000047061273231111400264130ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include "sample1.h" // Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; } // Returns true iff n is a prime number. bool IsPrime(int n) { // Trivial case 1: small numbers if (n <= 1) return false; // Trivial case 2: even numbers if (n % 2 == 0) return n == 2; // Now, we have that n is odd and n >= 3. // Try to divide n by every odd number i, starting from 3 for (int i = 3; ; i += 2) { // We only have to try i up to the squre root of n if (i > n/i) break; // Now, we have i <= n/i < n. // If n is divisible by i, n is not prime. if (n % i == 0) return false; } // n has no integer factor in the range (1, n), and thus is prime. return true; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample1.h000066400000000000000000000036211273231111400262500ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE1_H_ #define GTEST_SAMPLES_SAMPLE1_H_ // Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n); // Returns true iff n is a prime number. bool IsPrime(int n); #endif // GTEST_SAMPLES_SAMPLE1_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample10_unittest.cc000066400000000000000000000116751273231111400304350ustar00rootroot00000000000000// Copyright 2009 Google Inc. All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to use Google Test listener API to implement // a primitive leak checker. #include #include #include "gtest/gtest.h" using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; namespace { // We will track memory used by this class. class Water { public: // Normal Water declarations go here. // operator new and operator delete help us control water allocation. void* operator new(size_t allocation_size) { allocated_++; return malloc(allocation_size); } void operator delete(void* block, size_t /* allocation_size */) { allocated_--; free(block); } static int allocated() { return allocated_; } private: static int allocated_; }; int Water::allocated_ = 0; // This event listener monitors how many Water objects are created and // destroyed by each test, and reports a failure if a test leaks some Water // objects. It does this by comparing the number of live Water objects at // the beginning of a test and at the end of a test. class LeakChecker : public EmptyTestEventListener { private: // Called before a test starts. virtual void OnTestStart(const TestInfo& /* test_info */) { initially_allocated_ = Water::allocated(); } // Called after a test ends. virtual void OnTestEnd(const TestInfo& /* test_info */) { int difference = Water::allocated() - initially_allocated_; // You can generate a failure in any event handler except // OnTestPartResult. Just use an appropriate Google Test assertion to do // it. EXPECT_LE(difference, 0) << "Leaked " << difference << " unit(s) of Water!"; } int initially_allocated_; }; TEST(ListenersTest, DoesNotLeak) { Water* water = new Water; delete water; } // This should fail when the --check_for_leaks command line flag is // specified. TEST(ListenersTest, LeaksWater) { Water* water = new Water; EXPECT_TRUE(water != NULL); } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); bool check_for_leaks = false; if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0 ) check_for_leaks = true; else printf("%s\n", "Run this program with --check_for_leaks to enable " "custom leak checking in the tests."); // If we are given the --check_for_leaks command line flag, installs the // leak checker. if (check_for_leaks) { TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); // Adds the leak checker to the end of the test event listener list, // after the default text output printer and the default XML report // generator. // // The order is important - it ensures that failures generated in the // leak checker's OnTestEnd() method are processed by the text and XML // printers *before* their OnTestEnd() methods are called, such that // they are attributed to the right test. Remember that a listener // receives an OnXyzStart event *after* listeners preceding it in the // list received that event, and receives an OnXyzEnd event *before* // listeners preceding it. // // We don't need to worry about deleting the new listener later, as // Google Test will do it. listeners.Append(new LeakChecker); } return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample1_unittest.cc000066400000000000000000000120111273231111400303360ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // This sample shows how to write a simple unit test for a function, // using Google C++ testing framework. // // Writing a unit test using Google C++ testing framework is easy as 1-2-3: // Step 1. Include necessary header files such that the stuff your // test logic needs is declared. // // Don't forget gtest.h, which declares the testing framework. #include #include "sample1.h" #include "gtest/gtest.h" // Step 2. Use the TEST macro to define your tests. // // TEST has two parameters: the test case name and the test name. // After using the macro, you should define your test logic between a // pair of braces. You can use a bunch of macros to indicate the // success or failure of a test. EXPECT_TRUE and EXPECT_EQ are // examples of such macros. For a complete list, see gtest.h. // // // // In Google Test, tests are grouped into test cases. This is how we // keep test code organized. You should put logically related tests // into the same test case. // // The test case name and the test name should both be valid C++ // identifiers. And you should not use underscore (_) in the names. // // Google Test guarantees that each test you define is run exactly // once, but it makes no guarantee on the order the tests are // executed. Therefore, you should write your tests in such a way // that their results don't depend on their order. // // // Tests Factorial(). // Tests factorial of negative numbers. TEST(FactorialTest, Negative) { // This test is named "Negative", and belongs to the "FactorialTest" // test case. EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_GT(Factorial(-10), 0); // // // EXPECT_EQ(expected, actual) is the same as // // EXPECT_TRUE((expected) == (actual)) // // except that it will print both the expected value and the actual // value when the assertion fails. This is very helpful for // debugging. Therefore in this case EXPECT_EQ is preferred. // // On the other hand, EXPECT_TRUE accepts any Boolean expression, // and is thus more general. // // } // Tests factorial of 0. TEST(FactorialTest, Zero) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, Positive) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } // Tests IsPrime() // Tests negative input. TEST(IsPrimeTest, Negative) { // This test belongs to the IsPrimeTest test case. EXPECT_FALSE(IsPrime(-1)); EXPECT_FALSE(IsPrime(-2)); EXPECT_FALSE(IsPrime(INT_MIN)); } // Tests some trivial cases. TEST(IsPrimeTest, Trivial) { EXPECT_FALSE(IsPrime(0)); EXPECT_FALSE(IsPrime(1)); EXPECT_TRUE(IsPrime(2)); EXPECT_TRUE(IsPrime(3)); } // Tests positive input. TEST(IsPrimeTest, Positive) { EXPECT_FALSE(IsPrime(4)); EXPECT_TRUE(IsPrime(5)); EXPECT_FALSE(IsPrime(6)); EXPECT_TRUE(IsPrime(23)); } // Step 3. Call RUN_ALL_TESTS() in main(). // // We do this by linking in src/gtest_main.cc file, which consists of // a main() function which calls RUN_ALL_TESTS() for us. // // This runs all the tests you've defined, prints the result, and // returns 0 if successful, or 1 otherwise. // // Did you notice that we didn't register the tests? The // RUN_ALL_TESTS() macro magically knows about all the tests we // defined. Isn't this convenient? mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample2.cc000066400000000000000000000043721273231111400264130ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include "sample2.h" #include // Clones a 0-terminated C string, allocating memory using new. const char* MyString::CloneCString(const char* a_c_string) { if (a_c_string == NULL) return NULL; const size_t len = strlen(a_c_string); char* const clone = new char[ len + 1 ]; memcpy(clone, a_c_string, len + 1); return clone; } // Sets the 0-terminated C string this MyString object // represents. void MyString::Set(const char* a_c_string) { // Makes sure this works when c_string == c_string_ const char* const temp = MyString::CloneCString(a_c_string); delete[] c_string_; c_string_ = temp; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample2.h000066400000000000000000000056761273231111400262650ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE2_H_ #define GTEST_SAMPLES_SAMPLE2_H_ #include // A simple string class. class MyString { private: const char* c_string_; const MyString& operator=(const MyString& rhs); public: // Clones a 0-terminated C string, allocating memory using new. static const char* CloneCString(const char* a_c_string); //////////////////////////////////////////////////////////// // // C'tors // The default c'tor constructs a NULL string. MyString() : c_string_(NULL) {} // Constructs a MyString by cloning a 0-terminated C string. explicit MyString(const char* a_c_string) : c_string_(NULL) { Set(a_c_string); } // Copy c'tor MyString(const MyString& string) : c_string_(NULL) { Set(string.c_string_); } //////////////////////////////////////////////////////////// // // D'tor. MyString is intended to be a final class, so the d'tor // doesn't need to be virtual. ~MyString() { delete[] c_string_; } // Gets the 0-terminated C string this MyString object represents. const char* c_string() const { return c_string_; } size_t Length() const { return c_string_ == NULL ? 0 : strlen(c_string_); } // Sets the 0-terminated C string this MyString object represents. void Set(const char* c_string); }; #endif // GTEST_SAMPLES_SAMPLE2_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample2_unittest.cc000066400000000000000000000075261273231111400303560ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // This sample shows how to write a more complex unit test for a class // that has multiple member functions. // // Usually, it's a good idea to have one test for each method in your // class. You don't have to do that exactly, but it helps to keep // your tests organized. You may also throw in additional tests as // needed. #include "sample2.h" #include "gtest/gtest.h" // In this example, we test the MyString class (a simple string). // Tests the default c'tor. TEST(MyString, DefaultConstructor) { const MyString s; // Asserts that s.c_string() returns NULL. // // // // If we write NULL instead of // // static_cast(NULL) // // in this assertion, it will generate a warning on gcc 3.4. The // reason is that EXPECT_EQ needs to know the types of its // arguments in order to print them when it fails. Since NULL is // #defined as 0, the compiler will use the formatter function for // int to print it. However, gcc thinks that NULL should be used as // a pointer, not an int, and therefore complains. // // The root of the problem is C++'s lack of distinction between the // integer number 0 and the null pointer constant. Unfortunately, // we have to live with this fact. // // EXPECT_STREQ(NULL, s.c_string()); EXPECT_EQ(0u, s.Length()); } const char kHelloString[] = "Hello, world!"; // Tests the c'tor that accepts a C string. TEST(MyString, ConstructorFromCString) { const MyString s(kHelloString); EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1, s.Length()); } // Tests the copy c'tor. TEST(MyString, CopyConstructor) { const MyString s1(kHelloString); const MyString s2 = s1; EXPECT_EQ(0, strcmp(s2.c_string(), kHelloString)); } // Tests the Set method. TEST(MyString, Set) { MyString s; s.Set(kHelloString); EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); // Set should work when the input pointer is the same as the one // already in the MyString object. s.Set(s.c_string()); EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); // Can we set the MyString to NULL? s.Set(NULL); EXPECT_STREQ(NULL, s.c_string()); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample3-inl.h000066400000000000000000000123651273231111400270370ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE3_INL_H_ #define GTEST_SAMPLES_SAMPLE3_INL_H_ #include // Queue is a simple queue implemented as a singled-linked list. // // The element type must support copy constructor. template // E is the element type class Queue; // QueueNode is a node in a Queue, which consists of an element of // type E and a pointer to the next node. template // E is the element type class QueueNode { friend class Queue; public: // Gets the element in this node. const E& element() const { return element_; } // Gets the next node in the queue. QueueNode* next() { return next_; } const QueueNode* next() const { return next_; } private: // Creates a node with a given element value. The next pointer is // set to NULL. explicit QueueNode(const E& an_element) : element_(an_element), next_(NULL) {} // We disable the default assignment operator and copy c'tor. const QueueNode& operator = (const QueueNode&); QueueNode(const QueueNode&); E element_; QueueNode* next_; }; template // E is the element type. class Queue { public: // Creates an empty queue. Queue() : head_(NULL), last_(NULL), size_(0) {} // D'tor. Clears the queue. ~Queue() { Clear(); } // Clears the queue. void Clear() { if (size_ > 0) { // 1. Deletes every node. QueueNode* node = head_; QueueNode* next = node->next(); for (; ;) { delete node; node = next; if (node == NULL) break; next = node->next(); } // 2. Resets the member variables. head_ = last_ = NULL; size_ = 0; } } // Gets the number of elements. size_t Size() const { return size_; } // Gets the first element of the queue, or NULL if the queue is empty. QueueNode* Head() { return head_; } const QueueNode* Head() const { return head_; } // Gets the last element of the queue, or NULL if the queue is empty. QueueNode* Last() { return last_; } const QueueNode* Last() const { return last_; } // Adds an element to the end of the queue. A copy of the element is // created using the copy constructor, and then stored in the queue. // Changes made to the element in the queue doesn't affect the source // object, and vice versa. void Enqueue(const E& element) { QueueNode* new_node = new QueueNode(element); if (size_ == 0) { head_ = last_ = new_node; size_ = 1; } else { last_->next_ = new_node; last_ = new_node; size_++; } } // Removes the head of the queue and returns it. Returns NULL if // the queue is empty. E* Dequeue() { if (size_ == 0) { return NULL; } const QueueNode* const old_head = head_; head_ = head_->next_; size_--; if (size_ == 0) { last_ = NULL; } E* element = new E(old_head->element()); delete old_head; return element; } // Applies a function/functor on each element of the queue, and // returns the result in a new queue. The original queue is not // affected. template Queue* Map(F function) const { Queue* new_queue = new Queue(); for (const QueueNode* node = head_; node != NULL; node = node->next_) { new_queue->Enqueue(function(node->element())); } return new_queue; } private: QueueNode* head_; // The first node of the queue. QueueNode* last_; // The last node of the queue. size_t size_; // The number of elements in the queue. // We disallow copying a queue. Queue(const Queue&); const Queue& operator = (const Queue&); }; #endif // GTEST_SAMPLES_SAMPLE3_INL_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample3_unittest.cc000066400000000000000000000123471273231111400303540ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // In this example, we use a more advanced feature of Google Test called // test fixture. // // A test fixture is a place to hold objects and functions shared by // all tests in a test case. Using a test fixture avoids duplicating // the test code necessary to initialize and cleanup those common // objects for each test. It is also useful for defining sub-routines // that your tests need to invoke a lot. // // // // The tests share the test fixture in the sense of code sharing, not // data sharing. Each test is given its own fresh copy of the // fixture. You cannot expect the data modified by one test to be // passed on to another test, which is a bad idea. // // The reason for this design is that tests should be independent and // repeatable. In particular, a test should not fail as the result of // another test's failure. If one test depends on info produced by // another test, then the two tests should really be one big test. // // The macros for indicating the success/failure of a test // (EXPECT_TRUE, FAIL, etc) need to know what the current test is // (when Google Test prints the test result, it tells you which test // each failure belongs to). Technically, these macros invoke a // member function of the Test class. Therefore, you cannot use them // in a global function. That's why you should put test sub-routines // in a test fixture. // // #include "sample3-inl.h" #include "gtest/gtest.h" // To use a test fixture, derive a class from testing::Test. class QueueTest : public testing::Test { protected: // You should make the members protected s.t. they can be // accessed from sub-classes. // virtual void SetUp() will be called before each test is run. You // should define it if you need to initialize the varaibles. // Otherwise, this can be skipped. virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() will be called after each test is run. // You should define it if there is cleanup work to do. Otherwise, // you don't have to provide it. // // virtual void TearDown() { // } // A helper function that some test uses. static int Double(int n) { return 2*n; } // A helper function for testing Queue::Map(). void MapTester(const Queue * q) { // Creates a new queue, where each element is twice as big as the // corresponding one in q. const Queue * const new_q = q->Map(Double); // Verifies that the new queue has the same size as q. ASSERT_EQ(q->Size(), new_q->Size()); // Verifies the relationship between the elements of the two queues. for ( const QueueNode * n1 = q->Head(), * n2 = new_q->Head(); n1 != NULL; n1 = n1->next(), n2 = n2->next() ) { EXPECT_EQ(2 * n1->element(), n2->element()); } delete new_q; } // Declares the variables your tests want to use. Queue q0_; Queue q1_; Queue q2_; }; // When you have a test fixture, you define a test using TEST_F // instead of TEST. // Tests the default c'tor. TEST_F(QueueTest, DefaultConstructor) { // You can access data in the test fixture here. EXPECT_EQ(0u, q0_.Size()); } // Tests Dequeue(). TEST_F(QueueTest, Dequeue) { int * n = q0_.Dequeue(); EXPECT_TRUE(n == NULL); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0u, q1_.Size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1u, q2_.Size()); delete n; } // Tests the Queue::Map() function. TEST_F(QueueTest, Map) { MapTester(&q0_); MapTester(&q1_); MapTester(&q2_); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample4.cc000066400000000000000000000036071273231111400264150ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #include #include "sample4.h" // Returns the current counter value, and increments it. int Counter::Increment() { return counter_++; } // Prints the current counter value to STDOUT. void Counter::Print() const { printf("%d", counter_); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample4.h000066400000000000000000000040431273231111400262520ustar00rootroot00000000000000// 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. // A sample program demonstrating using Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_SAMPLES_SAMPLE4_H_ #define GTEST_SAMPLES_SAMPLE4_H_ // A simple monotonic counter. class Counter { private: int counter_; public: // Creates a counter that starts at 0. Counter() : counter_(0) {} // Returns the current counter value, and increments it. int Increment(); // Prints the current counter value to STDOUT. void Print() const; }; #endif // GTEST_SAMPLES_SAMPLE4_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample4_unittest.cc000066400000000000000000000035651273231111400303570ustar00rootroot00000000000000// 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) #include "gtest/gtest.h" #include "sample4.h" // Tests the Increment() method. TEST(Counter, Increment) { Counter c; // EXPECT_EQ() evaluates its arguments exactly once, so they // can have side effects. EXPECT_EQ(0, c.Increment()); EXPECT_EQ(1, c.Increment()); EXPECT_EQ(2, c.Increment()); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample5_unittest.cc000066400000000000000000000146761273231111400303650ustar00rootroot00000000000000// 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) // This sample teaches how to reuse a test fixture in multiple test // cases by deriving sub-fixtures from it. // // When you define a test fixture, you specify the name of the test // case that will use this fixture. Therefore, a test fixture can // be used by only one test case. // // Sometimes, more than one test cases may want to use the same or // slightly different test fixtures. For example, you may want to // make sure that all tests for a GUI library don't leak important // system resources like fonts and brushes. In Google Test, you do // this by putting the shared logic in a super (as in "super class") // test fixture, and then have each test case use a fixture derived // from this super fixture. #include #include #include "sample3-inl.h" #include "gtest/gtest.h" #include "sample1.h" // In this sample, we want to ensure that every test finishes within // ~5 seconds. If a test takes longer to run, we consider it a // failure. // // We put the code for timing a test in a test fixture called // "QuickTest". QuickTest is intended to be the super fixture that // other fixtures derive from, therefore there is no test case with // the name "QuickTest". This is OK. // // Later, we will derive multiple test fixtures from QuickTest. class QuickTest : public testing::Test { protected: // Remember that SetUp() is run immediately before a test starts. // This is a good place to record the start time. virtual void SetUp() { start_time_ = time(NULL); } // TearDown() is invoked immediately after a test finishes. Here we // check if the test was too slow. virtual void TearDown() { // Gets the time when the test finishes const time_t end_time = time(NULL); // Asserts that the test took no more than ~5 seconds. Did you // know that you can use assertions in SetUp() and TearDown() as // well? EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; } // The UTC time (in seconds) when the test starts time_t start_time_; }; // We derive a fixture named IntegerFunctionTest from the QuickTest // fixture. All tests using this fixture will be automatically // required to be quick. class IntegerFunctionTest : public QuickTest { // We don't need any more logic than already in the QuickTest fixture. // Therefore the body is empty. }; // Now we can write tests in the IntegerFunctionTest test case. // Tests Factorial() TEST_F(IntegerFunctionTest, Factorial) { // Tests factorial of negative numbers. EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_GT(Factorial(-10), 0); // Tests factorial of 0. EXPECT_EQ(1, Factorial(0)); // Tests factorial of positive numbers. EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } // Tests IsPrime() TEST_F(IntegerFunctionTest, IsPrime) { // Tests negative input. EXPECT_FALSE(IsPrime(-1)); EXPECT_FALSE(IsPrime(-2)); EXPECT_FALSE(IsPrime(INT_MIN)); // Tests some trivial cases. EXPECT_FALSE(IsPrime(0)); EXPECT_FALSE(IsPrime(1)); EXPECT_TRUE(IsPrime(2)); EXPECT_TRUE(IsPrime(3)); // Tests positive input. EXPECT_FALSE(IsPrime(4)); EXPECT_TRUE(IsPrime(5)); EXPECT_FALSE(IsPrime(6)); EXPECT_TRUE(IsPrime(23)); } // The next test case (named "QueueTest") also needs to be quick, so // we derive another fixture from QuickTest. // // The QueueTest test fixture has some logic and shared objects in // addition to what's in QuickTest already. We define the additional // stuff inside the body of the test fixture, as usual. class QueueTest : public QuickTest { protected: virtual void SetUp() { // First, we need to set up the super fixture (QuickTest). QuickTest::SetUp(); // Second, some additional setup for this fixture. q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // By default, TearDown() inherits the behavior of // QuickTest::TearDown(). As we have no additional cleaning work // for QueueTest, we omit it here. // // virtual void TearDown() { // QuickTest::TearDown(); // } Queue q0_; Queue q1_; Queue q2_; }; // Now, let's write tests using the QueueTest fixture. // Tests the default constructor. TEST_F(QueueTest, DefaultConstructor) { EXPECT_EQ(0u, q0_.Size()); } // Tests Dequeue(). TEST_F(QueueTest, Dequeue) { int* n = q0_.Dequeue(); EXPECT_TRUE(n == NULL); n = q1_.Dequeue(); EXPECT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0u, q1_.Size()); delete n; n = q2_.Dequeue(); EXPECT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1u, q2_.Size()); delete n; } // If necessary, you can derive further test fixtures from a derived // fixture itself. For example, you can derive another fixture from // QueueTest. Google Test imposes no limit on how deep the hierarchy // can be. In practice, however, you probably don't want it to be too // deep as to be confusing. mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample6_unittest.cc000066400000000000000000000214351273231111400303550ustar00rootroot00000000000000// 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) // This sample shows how to test common properties of multiple // implementations of the same interface (aka interface tests). // The interface and its implementations are in this header. #include "prime_tables.h" #include "gtest/gtest.h" // First, we define some factory functions for creating instances of // the implementations. You may be able to skip this step if all your // implementations can be constructed the same way. template PrimeTable* CreatePrimeTable(); template <> PrimeTable* CreatePrimeTable() { return new OnTheFlyPrimeTable; } template <> PrimeTable* CreatePrimeTable() { return new PreCalculatedPrimeTable(10000); } // Then we define a test fixture class template. template class PrimeTableTest : public testing::Test { protected: // The ctor calls the factory function to create a prime table // implemented by T. PrimeTableTest() : table_(CreatePrimeTable()) {} virtual ~PrimeTableTest() { delete table_; } // Note that we test an implementation via the base interface // instead of the actual implementation class. This is important // for keeping the tests close to the real world scenario, where the // implementation is invoked via the base interface. It avoids // got-yas where the implementation class has a method that shadows // a method with the same name (but slightly different argument // types) in the base interface, for example. PrimeTable* const table_; }; #if GTEST_HAS_TYPED_TEST using testing::Types; // Google Test offers two ways for reusing tests for different types. // The first is called "typed tests". You should use it if you // already know *all* the types you are gonna exercise when you write // the tests. // To write a typed test case, first use // // TYPED_TEST_CASE(TestCaseName, TypeList); // // to declare it and specify the type parameters. As with TEST_F, // TestCaseName must match the test fixture name. // The list of types we want to test. typedef Types Implementations; TYPED_TEST_CASE(PrimeTableTest, Implementations); // Then use TYPED_TEST(TestCaseName, TestName) to define a typed test, // similar to TEST_F. TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) { // Inside the test body, you can refer to the type parameter by // TypeParam, and refer to the fixture class by TestFixture. We // don't need them in this example. // Since we are in the template world, C++ requires explicitly // writing 'this->' when referring to members of the fixture class. // This is something you have to learn to live with. EXPECT_FALSE(this->table_->IsPrime(-5)); EXPECT_FALSE(this->table_->IsPrime(0)); EXPECT_FALSE(this->table_->IsPrime(1)); EXPECT_FALSE(this->table_->IsPrime(4)); EXPECT_FALSE(this->table_->IsPrime(6)); EXPECT_FALSE(this->table_->IsPrime(100)); } TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(this->table_->IsPrime(2)); EXPECT_TRUE(this->table_->IsPrime(3)); EXPECT_TRUE(this->table_->IsPrime(5)); EXPECT_TRUE(this->table_->IsPrime(7)); EXPECT_TRUE(this->table_->IsPrime(11)); EXPECT_TRUE(this->table_->IsPrime(131)); } TYPED_TEST(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, this->table_->GetNextPrime(0)); EXPECT_EQ(3, this->table_->GetNextPrime(2)); EXPECT_EQ(5, this->table_->GetNextPrime(3)); EXPECT_EQ(7, this->table_->GetNextPrime(5)); EXPECT_EQ(11, this->table_->GetNextPrime(7)); EXPECT_EQ(131, this->table_->GetNextPrime(128)); } // That's it! Google Test will repeat each TYPED_TEST for each type // in the type list specified in TYPED_TEST_CASE. Sit back and be // happy that you don't have to define them multiple times. #endif // GTEST_HAS_TYPED_TEST #if GTEST_HAS_TYPED_TEST_P using testing::Types; // Sometimes, however, you don't yet know all the types that you want // to test when you write the tests. For example, if you are the // author of an interface and expect other people to implement it, you // might want to write a set of tests to make sure each implementation // conforms to some basic requirements, but you don't know what // implementations will be written in the future. // // How can you write the tests without committing to the type // parameters? That's what "type-parameterized tests" can do for you. // It is a bit more involved than typed tests, but in return you get a // test pattern that can be reused in many contexts, which is a big // win. Here's how you do it: // First, define a test fixture class template. Here we just reuse // the PrimeTableTest fixture defined earlier: template class PrimeTableTest2 : public PrimeTableTest { }; // Then, declare the test case. The argument is the name of the test // fixture, and also the name of the test case (as usual). The _P // suffix is for "parameterized" or "pattern". TYPED_TEST_CASE_P(PrimeTableTest2); // Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test, // similar to what you do with TEST_F. TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) { EXPECT_FALSE(this->table_->IsPrime(-5)); EXPECT_FALSE(this->table_->IsPrime(0)); EXPECT_FALSE(this->table_->IsPrime(1)); EXPECT_FALSE(this->table_->IsPrime(4)); EXPECT_FALSE(this->table_->IsPrime(6)); EXPECT_FALSE(this->table_->IsPrime(100)); } TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) { EXPECT_TRUE(this->table_->IsPrime(2)); EXPECT_TRUE(this->table_->IsPrime(3)); EXPECT_TRUE(this->table_->IsPrime(5)); EXPECT_TRUE(this->table_->IsPrime(7)); EXPECT_TRUE(this->table_->IsPrime(11)); EXPECT_TRUE(this->table_->IsPrime(131)); } TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) { EXPECT_EQ(2, this->table_->GetNextPrime(0)); EXPECT_EQ(3, this->table_->GetNextPrime(2)); EXPECT_EQ(5, this->table_->GetNextPrime(3)); EXPECT_EQ(7, this->table_->GetNextPrime(5)); EXPECT_EQ(11, this->table_->GetNextPrime(7)); EXPECT_EQ(131, this->table_->GetNextPrime(128)); } // Type-parameterized tests involve one extra step: you have to // enumerate the tests you defined: REGISTER_TYPED_TEST_CASE_P( PrimeTableTest2, // The first argument is the test case name. // The rest of the arguments are the test names. ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime); // At this point the test pattern is done. However, you don't have // any real test yet as you haven't said which types you want to run // the tests with. // To turn the abstract test pattern into real tests, you instantiate // it with a list of types. Usually the test pattern will be defined // in a .h file, and anyone can #include and instantiate it. You can // even instantiate it more than once in the same program. To tell // different instances apart, you give each of them a name, which will // become part of the test case name and can be used in test filters. // The list of types we want to test. Note that it doesn't have to be // defined at the time we write the TYPED_TEST_P()s. typedef Types PrimeTableImplementations; INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name PrimeTableTest2, // Test case name PrimeTableImplementations); // Type list #endif // GTEST_HAS_TYPED_TEST_P mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample7_unittest.cc000066400000000000000000000117531273231111400303600ustar00rootroot00000000000000// 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) // This sample shows how to test common properties of multiple // implementations of an interface (aka interface tests) using // value-parameterized tests. Each test in the test case has // a parameter that is an interface pointer to an implementation // tested. // The interface and its implementations are in this header. #include "prime_tables.h" #include "gtest/gtest.h" #if GTEST_HAS_PARAM_TEST using ::testing::TestWithParam; using ::testing::Values; // As a general rule, to prevent a test from affecting the tests that come // after it, you should create and destroy the tested objects for each test // instead of reusing them. In this sample we will define a simple factory // function for PrimeTable objects. We will instantiate objects in test's // SetUp() method and delete them in TearDown() method. typedef PrimeTable* CreatePrimeTableFunc(); PrimeTable* CreateOnTheFlyPrimeTable() { return new OnTheFlyPrimeTable(); } template PrimeTable* CreatePreCalculatedPrimeTable() { return new PreCalculatedPrimeTable(max_precalculated); } // Inside the test body, fixture constructor, SetUp(), and TearDown() you // can refer to the test parameter by GetParam(). In this case, the test // parameter is a factory function which we call in fixture's SetUp() to // create and store an instance of PrimeTable. class PrimeTableTest : public TestWithParam { public: virtual ~PrimeTableTest() { delete table_; } virtual void SetUp() { table_ = (*GetParam())(); } virtual void TearDown() { delete table_; table_ = NULL; } protected: PrimeTable* table_; }; TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { EXPECT_FALSE(table_->IsPrime(-5)); EXPECT_FALSE(table_->IsPrime(0)); EXPECT_FALSE(table_->IsPrime(1)); EXPECT_FALSE(table_->IsPrime(4)); EXPECT_FALSE(table_->IsPrime(6)); EXPECT_FALSE(table_->IsPrime(100)); } TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(table_->IsPrime(2)); EXPECT_TRUE(table_->IsPrime(3)); EXPECT_TRUE(table_->IsPrime(5)); EXPECT_TRUE(table_->IsPrime(7)); EXPECT_TRUE(table_->IsPrime(11)); EXPECT_TRUE(table_->IsPrime(131)); } TEST_P(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, table_->GetNextPrime(0)); EXPECT_EQ(3, table_->GetNextPrime(2)); EXPECT_EQ(5, table_->GetNextPrime(3)); EXPECT_EQ(7, table_->GetNextPrime(5)); EXPECT_EQ(11, table_->GetNextPrime(7)); EXPECT_EQ(131, table_->GetNextPrime(128)); } // In order to run value-parameterized tests, you need to instantiate them, // or bind them to a list of values which will be used as test parameters. // You can instantiate them in a different translation module, or even // instantiate them several times. // // Here, we instantiate our tests with a list of two PrimeTable object // factory functions: INSTANTIATE_TEST_CASE_P( OnTheFlyAndPreCalculated, PrimeTableTest, Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>)); #else // Google Test may not support value-parameterized tests with some // compilers. If we use conditional compilation to compile out all // code referring to the gtest_main library, MSVC linker will not link // that library at all and consequently complain about missing entry // point defined in that library (fatal error LNK1561: entry point // must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_PARAM_TEST mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample8_unittest.cc000066400000000000000000000154401273231111400303560ustar00rootroot00000000000000// 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) // This sample shows how to test code relying on some global flag variables. // Combine() helps with generating all possible combinations of such flags, // and each test is given one combination as a parameter. // Use class definitions to test from this header. #include "prime_tables.h" #include "gtest/gtest.h" #if GTEST_HAS_COMBINE // Suppose we want to introduce a new, improved implementation of PrimeTable // which combines speed of PrecalcPrimeTable and versatility of // OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both // PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more // appropriate under the circumstances. But in low memory conditions, it can be // told to instantiate without PrecalcPrimeTable instance at all and use only // OnTheFlyPrimeTable. class HybridPrimeTable : public PrimeTable { public: HybridPrimeTable(bool force_on_the_fly, int max_precalculated) : on_the_fly_impl_(new OnTheFlyPrimeTable), precalc_impl_(force_on_the_fly ? NULL : new PreCalculatedPrimeTable(max_precalculated)), max_precalculated_(max_precalculated) {} virtual ~HybridPrimeTable() { delete on_the_fly_impl_; delete precalc_impl_; } virtual bool IsPrime(int n) const { if (precalc_impl_ != NULL && n < max_precalculated_) return precalc_impl_->IsPrime(n); else return on_the_fly_impl_->IsPrime(n); } virtual int GetNextPrime(int p) const { int next_prime = -1; if (precalc_impl_ != NULL && p < max_precalculated_) next_prime = precalc_impl_->GetNextPrime(p); return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p); } private: OnTheFlyPrimeTable* on_the_fly_impl_; PreCalculatedPrimeTable* precalc_impl_; int max_precalculated_; }; using ::testing::TestWithParam; using ::testing::Bool; using ::testing::Values; using ::testing::Combine; // To test all code paths for HybridPrimeTable we must test it with numbers // both within and outside PreCalculatedPrimeTable's capacity and also with // PreCalculatedPrimeTable disabled. We do this by defining fixture which will // accept different combinations of parameters for instantiating a // HybridPrimeTable instance. class PrimeTableTest : public TestWithParam< ::std::tr1::tuple > { protected: virtual void SetUp() { // This can be written as // // bool force_on_the_fly; // int max_precalculated; // tie(force_on_the_fly, max_precalculated) = GetParam(); // // once the Google C++ Style Guide allows use of ::std::tr1::tie. // bool force_on_the_fly = ::std::tr1::get<0>(GetParam()); int max_precalculated = ::std::tr1::get<1>(GetParam()); table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated); } virtual void TearDown() { delete table_; table_ = NULL; } HybridPrimeTable* table_; }; TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { // Inside the test body, you can refer to the test parameter by GetParam(). // In this case, the test parameter is a PrimeTable interface pointer which // we can use directly. // Please note that you can also save it in the fixture's SetUp() method // or constructor and use saved copy in the tests. EXPECT_FALSE(table_->IsPrime(-5)); EXPECT_FALSE(table_->IsPrime(0)); EXPECT_FALSE(table_->IsPrime(1)); EXPECT_FALSE(table_->IsPrime(4)); EXPECT_FALSE(table_->IsPrime(6)); EXPECT_FALSE(table_->IsPrime(100)); } TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { EXPECT_TRUE(table_->IsPrime(2)); EXPECT_TRUE(table_->IsPrime(3)); EXPECT_TRUE(table_->IsPrime(5)); EXPECT_TRUE(table_->IsPrime(7)); EXPECT_TRUE(table_->IsPrime(11)); EXPECT_TRUE(table_->IsPrime(131)); } TEST_P(PrimeTableTest, CanGetNextPrime) { EXPECT_EQ(2, table_->GetNextPrime(0)); EXPECT_EQ(3, table_->GetNextPrime(2)); EXPECT_EQ(5, table_->GetNextPrime(3)); EXPECT_EQ(7, table_->GetNextPrime(5)); EXPECT_EQ(11, table_->GetNextPrime(7)); EXPECT_EQ(131, table_->GetNextPrime(128)); } // In order to run value-parameterized tests, you need to instantiate them, // or bind them to a list of values which will be used as test parameters. // You can instantiate them in a different translation module, or even // instantiate them several times. // // Here, we instantiate our tests with a list of parameters. We must combine // all variations of the boolean flag suppressing PrecalcPrimeTable and some // meaningful values for tests. We choose a small value (1), and a value that // will put some of the tested numbers beyond the capability of the // PrecalcPrimeTable instance and some inside it (10). Combine will produce all // possible combinations. INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters, PrimeTableTest, Combine(Bool(), Values(1, 10))); #else // Google Test may not support Combine() with some compilers. If we // use conditional compilation to compile out all code referring to // the gtest_main library, MSVC linker will not link that library at // all and consequently complain about missing entry point defined in // that library (fatal error LNK1561: entry point must be // defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_COMBINE mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/samples/sample9_unittest.cc000066400000000000000000000134771273231111400303670ustar00rootroot00000000000000// Copyright 2009 Google Inc. All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // This sample shows how to use Google Test listener API to implement // an alternative console output and how to use the UnitTest reflection API // to enumerate test cases and tests and to inspect their results. #include #include "gtest/gtest.h" using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; namespace { // Provides alternative output mode which produces minimal amount of // information about tests. class TersePrinter : public EmptyTestEventListener { private: // Called before any test activity starts. virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {} // Called after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) { fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED"); fflush(stdout); } // Called before a test starts. virtual void OnTestStart(const TestInfo& test_info) { fprintf(stdout, "*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); fflush(stdout); } // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const TestPartResult& test_part_result) { fprintf(stdout, "%s in %s:%d\n%s\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), test_part_result.line_number(), test_part_result.summary()); fflush(stdout); } // Called after a test ends. virtual void OnTestEnd(const TestInfo& test_info) { fprintf(stdout, "*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); fflush(stdout); } }; // class TersePrinter TEST(CustomOutputTest, PrintsMessage) { printf("Printing something from the test body...\n"); } TEST(CustomOutputTest, Succeeds) { SUCCEED() << "SUCCEED() has been invoked from here"; } TEST(CustomOutputTest, Fails) { EXPECT_EQ(1, 2) << "This test fails in order to demonstrate alternative failure messages"; } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); bool terse_output = false; if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 ) terse_output = true; else printf("%s\n", "Run this program with --terse_output to change the way " "it prints its output."); UnitTest& unit_test = *UnitTest::GetInstance(); // If we are given the --terse_output command line flag, suppresses the // standard output and attaches own result printer. if (terse_output) { TestEventListeners& listeners = unit_test.listeners(); // Removes the default console output listener from the list so it will // not receive events from Google Test and won't print any output. Since // this operation transfers ownership of the listener to the caller we // have to delete it as well. delete listeners.Release(listeners.default_result_printer()); // Adds the custom output listener to the list. It will now receive // events from Google Test and print the alternative output. We don't // have to worry about deleting it since Google Test assumes ownership // over it after adding it to the list. listeners.Append(new TersePrinter); } int ret_val = RUN_ALL_TESTS(); // This is an example of using the UnitTest reflection API to inspect test // results. Here we discount failures from the tests we expected to fail. int unexpectedly_failed_tests = 0; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); // Counts failed tests that were not meant to fail (those without // 'Fails' in the name). if (test_info.result()->Failed() && strcmp(test_info.name(), "Fails") != 0) { unexpectedly_failed_tests++; } } } // Test that were meant to fail should not affect the test program outcome. if (unexpectedly_failed_tests == 0) ret_val = 0; return ret_val; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/000077500000000000000000000000001273231111400245565ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/fuse_gtest_files.py000077500000000000000000000211551273231111400304710ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2009, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """fuse_gtest_files.py v0.2.0 Fuses Google Test source code into a .h file and a .cc file. SYNOPSIS fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR Scans GTEST_ROOT_DIR for Google Test source code, and generates two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc. Then you can build your tests by adding OUTPUT_DIR to the include search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These two files contain everything you need to use Google Test. Hence you can "install" Google Test by copying them to wherever you want. GTEST_ROOT_DIR can be omitted and defaults to the parent directory of the directory holding this script. EXAMPLES ./fuse_gtest_files.py fused_gtest ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest This tool is experimental. In particular, it assumes that there is no conditional inclusion of Google Test headers. Please report any problems to googletestframework@googlegroups.com. You can read http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for more information. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sets import sys # We assume that this file is in the scripts/ directory in the Google # Test root directory. DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') # Regex for matching '#include "gtest/..."'. INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gtest/.+)"') # Regex for matching '#include "src/..."'. INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"') # Where to find the source seed files. GTEST_H_SEED = 'include/gtest/gtest.h' GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h' GTEST_ALL_CC_SEED = 'src/gtest-all.cc' # Where to put the generated files. GTEST_H_OUTPUT = 'gtest/gtest.h' GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc' def VerifyFileExists(directory, relative_path): """Verifies that the given file exists; aborts on failure. relative_path is the file path relative to the given directory. """ if not os.path.isfile(os.path.join(directory, relative_path)): print 'ERROR: Cannot find %s in directory %s.' % (relative_path, directory) print ('Please either specify a valid project root directory ' 'or omit it on the command line.') sys.exit(1) def ValidateGTestRootDir(gtest_root): """Makes sure gtest_root points to a valid gtest root directory. The function aborts the program on failure. """ VerifyFileExists(gtest_root, GTEST_H_SEED) VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED) def VerifyOutputFile(output_dir, relative_path): """Verifies that the given output file path is valid. relative_path is relative to the output_dir directory. """ # Makes sure the output file either doesn't exist or can be overwritten. output_file = os.path.join(output_dir, relative_path) if os.path.exists(output_file): # TODO(wan@google.com): The following user-interaction doesn't # work with automated processes. We should provide a way for the # Makefile to force overwriting the files. print ('%s already exists in directory %s - overwrite it? (y/N) ' % (relative_path, output_dir)) answer = sys.stdin.readline().strip() if answer not in ['y', 'Y']: print 'ABORTED.' sys.exit(1) # Makes sure the directory holding the output file exists; creates # it and all its ancestors if necessary. parent_directory = os.path.dirname(output_file) if not os.path.isdir(parent_directory): os.makedirs(parent_directory) def ValidateOutputDir(output_dir): """Makes sure output_dir points to a valid output directory. The function aborts the program on failure. """ VerifyOutputFile(output_dir, GTEST_H_OUTPUT) VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT) def FuseGTestH(gtest_root, output_dir): """Scans folder gtest_root to generate gtest/gtest.h in output_dir.""" output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w') processed_files = sets.Set() # Holds all gtest headers we've processed. def ProcessFile(gtest_header_path): """Processes the given gtest header file.""" # We don't process the same header twice. if gtest_header_path in processed_files: return processed_files.add(gtest_header_path) # Reads each line in the given gtest header. for line in file(os.path.join(gtest_root, gtest_header_path), 'r'): m = INCLUDE_GTEST_FILE_REGEX.match(line) if m: # It's '#include "gtest/..."' - let's process it recursively. ProcessFile('include/' + m.group(1)) else: # Otherwise we copy the line unchanged to the output file. output_file.write(line) ProcessFile(GTEST_H_SEED) output_file.close() def FuseGTestAllCcToFile(gtest_root, output_file): """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file.""" processed_files = sets.Set() def ProcessFile(gtest_source_file): """Processes the given gtest source file.""" # We don't process the same #included file twice. if gtest_source_file in processed_files: return processed_files.add(gtest_source_file) # Reads each line in the given gtest source file. for line in file(os.path.join(gtest_root, gtest_source_file), 'r'): m = INCLUDE_GTEST_FILE_REGEX.match(line) if m: if 'include/' + m.group(1) == GTEST_SPI_H_SEED: # It's '#include "gtest/gtest-spi.h"'. This file is not # #included by "gtest/gtest.h", so we need to process it. ProcessFile(GTEST_SPI_H_SEED) else: # It's '#include "gtest/foo.h"' where foo is not gtest-spi. # We treat it as '#include "gtest/gtest.h"', as all other # gtest headers are being fused into gtest.h and cannot be # #included directly. # There is no need to #include "gtest/gtest.h" more than once. if not GTEST_H_SEED in processed_files: processed_files.add(GTEST_H_SEED) output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,)) else: m = INCLUDE_SRC_FILE_REGEX.match(line) if m: # It's '#include "src/foo"' - let's process it recursively. ProcessFile(m.group(1)) else: output_file.write(line) ProcessFile(GTEST_ALL_CC_SEED) def FuseGTestAllCc(gtest_root, output_dir): """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir.""" output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w') FuseGTestAllCcToFile(gtest_root, output_file) output_file.close() def FuseGTest(gtest_root, output_dir): """Fuses gtest.h and gtest-all.cc.""" ValidateGTestRootDir(gtest_root) ValidateOutputDir(output_dir) FuseGTestH(gtest_root, output_dir) FuseGTestAllCc(gtest_root, output_dir) def main(): argc = len(sys.argv) if argc == 2: # fuse_gtest_files.py OUTPUT_DIR FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1]) elif argc == 3: # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR FuseGTest(sys.argv[1], sys.argv[2]) else: print __doc__ sys.exit(1) if __name__ == '__main__': main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/gen_gtest_pred_impl.py000077500000000000000000000527421273231111400311570ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """gen_gtest_pred_impl.py v0.1 Generates the implementation of Google Test predicate assertions and accompanying tests. Usage: gen_gtest_pred_impl.py MAX_ARITY where MAX_ARITY is a positive integer. The command generates the implementation of up-to MAX_ARITY-ary predicate assertions, and writes it to file gtest_pred_impl.h in the directory where the script is. It also generates the accompanying unit test in file gtest_pred_impl_unittest.cc. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import sys import time # Where this script is. SCRIPT_DIR = os.path.dirname(sys.argv[0]) # Where to store the generated header. HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h') # Where to store the generated unit test. UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc') def HeaderPreamble(n): """Returns the preamble for the header file. Args: n: the maximum arity of the predicate macros to be generated. """ # A map that defines the values used in the preamble template. DEFS = { 'today' : time.strftime('%m/%d/%Y'), 'year' : time.strftime('%Y'), 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n), 'n' : n } return ( """// 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 %(today)s by command // '%(command)s'. 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 %(n)s. // 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()) """ % DEFS) def Arity(n): """Returns the English name of the given arity.""" if n < 0: return None elif n <= 3: return ['nullary', 'unary', 'binary', 'ternary'][n] else: return '%s-ary' % n def Title(word): """Returns the given word in title case. The difference between this and string's title() method is that Title('4-ary') is '4-ary' while '4-ary'.title() is '4-Ary'.""" return word[0].upper() + word[1:] def OneTo(n): """Returns the list [1, 2, 3, ..., n].""" return range(1, n + 1) def Iter(n, format, sep=''): """Given a positive integer n, a format string that contains 0 or more '%s' format specs, and optionally a separator string, returns the join of n strings, each formatted with the format string on an iterator ranged from 1 to n. Example: Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'. """ # How many '%s' specs are in format? spec_count = len(format.split('%s')) - 1 return sep.join([format % (spec_count * (i,)) for i in OneTo(n)]) def ImplementationForArity(n): """Returns the implementation of n-ary predicate assertions.""" # A map the defines the values used in the implementation template. DEFS = { 'n' : str(n), 'vs' : Iter(n, 'v%s', sep=', '), 'vts' : Iter(n, '#v%s', sep=', '), 'arity' : Arity(n), 'Arity' : Title(Arity(n)) } impl = """ // Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use // this in your code. template AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS impl += Iter(n, """, const char* e%s""") impl += """, Pred pred""" impl += Iter(n, """, const T%s& v%s""") impl += """) { if (pred(%(vs)s)) return AssertionSuccess(); """ % DEFS impl += ' return AssertionFailure() << pred_text << "("' impl += Iter(n, """ << e%s""", sep=' << ", "') impl += ' << ") evaluates to false, where"' impl += Iter(n, """ << "\\n" << e%s << " evaluates to " << v%s""") impl += """; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s. // Don't use this in your code. #define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\ GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s), \\ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use // this in your code. #define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\ GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS impl += Iter(n, """, \\ #v%s""") impl += """, \\ pred""" impl += Iter(n, """, \\ v%s""") impl += """), on_failure) // %(Arity)s predicate assertion macros. #define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED%(n)s(pred, %(vs)s) \\ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_) #define ASSERT_PRED%(n)s(pred, %(vs)s) \\ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_) """ % DEFS return impl def HeaderPostamble(): """Returns the postamble for the header file.""" return """ #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ """ def GenerateFile(path, content): """Given a file path and a content string, overwrites it with the given content.""" print 'Updating file %s . . .' % path f = file(path, 'w+') print >>f, content, f.close() print 'File %s has been updated.' % path def GenerateHeader(n): """Given the maximum arity n, updates the header file that implements the predicate assertions.""" GenerateFile(HEADER, HeaderPreamble(n) + ''.join([ImplementationForArity(i) for i in OneTo(n)]) + HeaderPostamble()) def UnitTestPreamble(): """Returns the preamble for the unit test file.""" # A map that defines the values used in the preamble template. DEFS = { 'today' : time.strftime('%m/%d/%Y'), 'year' : time.strftime('%Y'), 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]), } return ( """// 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 %(today)s by command // '%(command)s'. DO NOT EDIT BY HAND! // Regression test for gtest_pred_impl.h // // This file is generated by a script and quite long. If you intend to // learn how Google Test works by reading its unit tests, read // gtest_unittest.cc instead. // // This is intended as a regression test for the Google Test predicate // assertions. We compile it as part of the gtest_unittest target // only to keep the implementation tidy and compact, as it is quite // involved to set up the stage for testing Google Test using Google // Test itself. // // Currently, gtest_unittest takes ~11 seconds to run in the testing // daemon. In the future, if it grows too large and needs much more // time to finish, we should consider separating this file into a // stand-alone regression test. #include #include "gtest/gtest.h" #include "gtest/gtest-spi.h" // A user-defined data type. struct Bool { explicit Bool(int val) : value(val != 0) {} bool operator>(int n) const { return value > Bool(n).value; } Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } bool operator==(const Bool& rhs) const { return value == rhs.value; } bool value; }; // Enables Bool to be used in assertions. std::ostream& operator<<(std::ostream& os, const Bool& x) { return os << (x.value ? "true" : "false"); } """ % DEFS) def TestsForArity(n): """Returns the tests for n-ary predicate assertions.""" # A map that defines the values used in the template for the tests. DEFS = { 'n' : n, 'es' : Iter(n, 'e%s', sep=', '), 'vs' : Iter(n, 'v%s', sep=', '), 'vts' : Iter(n, '#v%s', sep=', '), 'tvs' : Iter(n, 'T%s v%s', sep=', '), 'int_vs' : Iter(n, 'int v%s', sep=', '), 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '), 'types' : Iter(n, 'typename T%s', sep=', '), 'v_sum' : Iter(n, 'v%s', sep=' + '), 'arity' : Arity(n), 'Arity' : Title(Arity(n)), } tests = ( """// Sample functions/functors for testing %(arity)s predicate assertions. // A %(arity)s predicate function. template <%(types)s> bool PredFunction%(n)s(%(tvs)s) { return %(v_sum)s > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction%(n)sInt(%(int_vs)s) { return %(v_sum)s > 0; } bool PredFunction%(n)sBool(%(Bool_vs)s) { return %(v_sum)s > 0; } """ % DEFS) tests += """ // A %(arity)s predicate functor. struct PredFunctor%(n)s { template <%(types)s> bool operator()(""" % DEFS tests += Iter(n, 'const T%s& v%s', sep=""", """) tests += """) { return %(v_sum)s > 0; } }; """ % DEFS tests += """ // A %(arity)s predicate-formatter function. template <%(types)s> testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS tests += Iter(n, 'const char* e%s', sep=""", """) tests += Iter(n, """, const T%s& v%s""") tests += """) { if (PredFunction%(n)s(%(vs)s)) return testing::AssertionSuccess(); return testing::AssertionFailure() << """ % DEFS tests += Iter(n, 'e%s', sep=' << " + " << ') tests += """ << " is expected to be positive, but evaluates to " << %(v_sum)s << "."; } """ % DEFS tests += """ // A %(arity)s predicate-formatter functor. struct PredFormatFunctor%(n)s { template <%(types)s> testing::AssertionResult operator()(""" % DEFS tests += Iter(n, 'const char* e%s', sep=""", """) tests += Iter(n, """, const T%s& v%s""") tests += """) const { return PredFormatFunction%(n)s(%(es)s, %(vs)s); } }; """ % DEFS tests += """ // Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s. class Predicate%(n)sTest : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false;""" % DEFS tests += """ """ + Iter(n, 'n%s_ = ') + """0; } """ tests += """ virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once.""" tests += ''.join([""" EXPECT_EQ(1, n%s_) << "The predicate assertion didn't evaluate argument %s " "exactly once.";""" % (i, i + 1) for i in OneTo(n)]) tests += """ // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; """ % DEFS tests += Iter(n, """ static int n%s_;""") tests += """ }; bool Predicate%(n)sTest::expected_to_finish_; bool Predicate%(n)sTest::finished_; """ % DEFS tests += Iter(n, """int Predicate%%(n)sTest::n%s_; """) % DEFS tests += """ typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest; typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest; typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest; typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest; """ % DEFS def GenTest(use_format, use_assert, expect_failure, use_functor, use_user_type): """Returns the test for a predicate assertion macro. Args: use_format: true iff the assertion is a *_PRED_FORMAT*. use_assert: true iff the assertion is a ASSERT_*. expect_failure: true iff the assertion is expected to fail. use_functor: true iff the first argument of the assertion is a functor (as opposed to a function) use_user_type: true iff the predicate functor/function takes argument(s) of a user-defined type. Example: GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior of a successful EXPECT_PRED_FORMATn() that takes a functor whose arguments have built-in types.""" if use_assert: assrt = 'ASSERT' # 'assert' is reserved, so we cannot use # that identifier here. else: assrt = 'EXPECT' assertion = assrt + '_PRED' if use_format: pred_format = 'PredFormat' assertion += '_FORMAT' else: pred_format = 'Pred' assertion += '%(n)s' % DEFS if use_functor: pred_format_type = 'functor' pred_format += 'Functor%(n)s()' else: pred_format_type = 'function' pred_format += 'Function%(n)s' if not use_format: if use_user_type: pred_format += 'Bool' else: pred_format += 'Int' test_name = pred_format_type.title() if use_user_type: arg_type = 'user-defined type (Bool)' test_name += 'OnUserType' if expect_failure: arg = 'Bool(n%s_++)' else: arg = 'Bool(++n%s_)' else: arg_type = 'built-in type (int)' test_name += 'OnBuiltInType' if expect_failure: arg = 'n%s_++' else: arg = '++n%s_' if expect_failure: successful_or_failed = 'failed' expected_or_not = 'expected.' test_name += 'Failure' else: successful_or_failed = 'successful' expected_or_not = 'UNEXPECTED!' test_name += 'Success' # A map that defines the values used in the test template. defs = DEFS.copy() defs.update({ 'assert' : assrt, 'assertion' : assertion, 'test_name' : test_name, 'pf_type' : pred_format_type, 'pf' : pred_format, 'arg_type' : arg_type, 'arg' : arg, 'successful' : successful_or_failed, 'expected' : expected_or_not, }) test = """ // Tests a %(successful)s %(assertion)s where the // predicate-formatter is a %(pf_type)s on a %(arg_type)s. TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs indent = (len(assertion) + 3)*' ' extra_indent = '' if expect_failure: extra_indent = ' ' if use_assert: test += """ expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT""" else: test += """ EXPECT_NONFATAL_FAILURE({ // NOLINT""" test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs test = test % defs test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs) test += ');\n' + extra_indent + ' finished_ = true;\n' if expect_failure: test += ' }, "");\n' test += '}\n' return test # Generates tests for all 2**6 = 64 combinations. tests += ''.join([GenTest(use_format, use_assert, expect_failure, use_functor, use_user_type) for use_format in [0, 1] for use_assert in [0, 1] for expect_failure in [0, 1] for use_functor in [0, 1] for use_user_type in [0, 1] ]) return tests def UnitTestPostamble(): """Returns the postamble for the tests.""" return '' def GenerateUnitTest(n): """Returns the tests for up-to n-ary predicate assertions.""" GenerateFile(UNIT_TEST, UnitTestPreamble() + ''.join([TestsForArity(i) for i in OneTo(n)]) + UnitTestPostamble()) def _Main(): """The entry point of the script. Generates the header file and its unit test.""" if len(sys.argv) != 2: print __doc__ print 'Author: ' + __author__ sys.exit(1) n = int(sys.argv[1]) GenerateHeader(n) GenerateUnitTest(n) if __name__ == '__main__': _Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/gtest-config.in000077500000000000000000000235471273231111400275150ustar00rootroot00000000000000#!/bin/sh # These variables are automatically filled in by the configure script. name="@PACKAGE_TARNAME@" version="@PACKAGE_VERSION@" show_usage() { echo "Usage: gtest-config [OPTIONS...]" } show_help() { show_usage cat <<\EOF The `gtest-config' script provides access to the necessary compile and linking flags to connect with Google C++ Testing Framework, both in a build prior to installation, and on the system proper after installation. The installation overrides may be issued in combination with any other queries, but will only affect installation queries if called on a built but not installed gtest. The installation queries may not be issued with any other types of queries, and only one installation query may be made at a time. The version queries and compiler flag queries may be combined as desired but not mixed. Different version queries are always combined with logical "and" semantics, and only the last of any particular query is used while all previous ones ignored. All versions must be specified as a sequence of numbers separated by periods. Compiler flag queries output the union of the sets of flags when combined. Examples: gtest-config --min-version=1.0 || echo "Insufficient Google Test version." g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp g++ $(gtest-config --ldflags --libs) -o foo foo.o # When using a built but not installed Google Test: g++ $(../../my_gtest_build/scripts/gtest-config ...) ... # When using an installed Google Test, but with installation overrides: export GTEST_PREFIX="/opt" g++ $(gtest-config --libdir="/opt/lib64" ...) ... Help: --usage brief usage information --help display this help message Installation Overrides: --prefix= overrides the installation prefix --exec-prefix= overrides the executable installation prefix --libdir= overrides the library installation prefix --includedir= overrides the header file installation prefix Installation Queries: --prefix installation prefix --exec-prefix executable installation prefix --libdir library installation directory --includedir header file installation directory --version the version of the Google Test installation Version Queries: --min-version=VERSION return 0 if the version is at least VERSION --exact-version=VERSION return 0 if the version is exactly VERSION --max-version=VERSION return 0 if the version is at most VERSION Compilation Flag Queries: --cppflags compile flags specific to the C-like preprocessors --cxxflags compile flags appropriate for C++ programs --ldflags linker flags --libs libraries for linking EOF } # This function bounds our version with a min and a max. It uses some clever # POSIX-compliant variable expansion to portably do all the work in the shell # and avoid any dependency on a particular "sed" or "awk" implementation. # Notable is that it will only ever compare the first 3 components of versions. # Further components will be cleanly stripped off. All versions must be # unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and # the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should # investigate expanding this via autom4te from AS_VERSION_COMPARE rather than # continuing to maintain our own shell version. check_versions() { major_version=${version%%.*} minor_version="0" point_version="0" if test "${version#*.}" != "${version}"; then minor_version=${version#*.} minor_version=${minor_version%%.*} fi if test "${version#*.*.}" != "${version}"; then point_version=${version#*.*.} point_version=${point_version%%.*} fi min_version="$1" min_major_version=${min_version%%.*} min_minor_version="0" min_point_version="0" if test "${min_version#*.}" != "${min_version}"; then min_minor_version=${min_version#*.} min_minor_version=${min_minor_version%%.*} fi if test "${min_version#*.*.}" != "${min_version}"; then min_point_version=${min_version#*.*.} min_point_version=${min_point_version%%.*} fi max_version="$2" max_major_version=${max_version%%.*} max_minor_version="0" max_point_version="0" if test "${max_version#*.}" != "${max_version}"; then max_minor_version=${max_version#*.} max_minor_version=${max_minor_version%%.*} fi if test "${max_version#*.*.}" != "${max_version}"; then max_point_version=${max_version#*.*.} max_point_version=${max_point_version%%.*} fi test $(($major_version)) -lt $(($min_major_version)) && exit 1 if test $(($major_version)) -eq $(($min_major_version)); then test $(($minor_version)) -lt $(($min_minor_version)) && exit 1 if test $(($minor_version)) -eq $(($min_minor_version)); then test $(($point_version)) -lt $(($min_point_version)) && exit 1 fi fi test $(($major_version)) -gt $(($max_major_version)) && exit 1 if test $(($major_version)) -eq $(($max_major_version)); then test $(($minor_version)) -gt $(($max_minor_version)) && exit 1 if test $(($minor_version)) -eq $(($max_minor_version)); then test $(($point_version)) -gt $(($max_point_version)) && exit 1 fi fi exit 0 } # Show the usage line when no arguments are specified. if test $# -eq 0; then show_usage exit 1 fi while test $# -gt 0; do case $1 in --usage) show_usage; exit 0;; --help) show_help; exit 0;; # Installation overrides --prefix=*) GTEST_PREFIX=${1#--prefix=};; --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};; --libdir=*) GTEST_LIBDIR=${1#--libdir=};; --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};; # Installation queries --prefix|--exec-prefix|--libdir|--includedir|--version) if test -n "${do_query}"; then show_usage exit 1 fi do_query=${1#--} ;; # Version checking --min-version=*) do_check_versions=yes min_version=${1#--min-version=} ;; --max-version=*) do_check_versions=yes max_version=${1#--max-version=} ;; --exact-version=*) do_check_versions=yes exact_version=${1#--exact-version=} ;; # Compiler flag output --cppflags) echo_cppflags=yes;; --cxxflags) echo_cxxflags=yes;; --ldflags) echo_ldflags=yes;; --libs) echo_libs=yes;; # Everything else is an error *) show_usage; exit 1;; esac shift done # These have defaults filled in by the configure script but can also be # overridden by environment variables or command line parameters. prefix="${GTEST_PREFIX:-@prefix@}" exec_prefix="${GTEST_EXEC_PREFIX:-@exec_prefix@}" libdir="${GTEST_LIBDIR:-@libdir@}" includedir="${GTEST_INCLUDEDIR:-@includedir@}" # We try and detect if our binary is not located at its installed location. If # it's not, we provide variables pointing to the source and build tree rather # than to the install tree. This allows building against a just-built gtest # rather than an installed gtest. bindir="@bindir@" this_relative_bindir=`dirname $0` this_bindir=`cd ${this_relative_bindir}; pwd -P` if test "${this_bindir}" = "${this_bindir%${bindir}}"; then # The path to the script doesn't end in the bindir sequence from Autoconf, # assume that we are in a build tree. build_dir=`dirname ${this_bindir}` src_dir=`cd ${this_bindir}; cd @top_srcdir@; pwd -P` # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we # should work to remove it, and/or remove libtool altogether, replacing it # with direct references to the library and a link path. gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_ldflags="" # We provide hooks to include from either the source or build dir, where the # build dir is always preferred. This will potentially allow us to write # build rules for generated headers and have them automatically be preferred # over provided versions. gtest_cppflags="-I${build_dir}/include -I${src_dir}/include" gtest_cxxflags="@PTHREAD_CFLAGS@" else # We're using an installed gtest, although it may be staged under some # prefix. Assume (as our own libraries do) that we can resolve the prefix, # and are present in the dynamic link paths. gtest_ldflags="-L${libdir}" gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_cppflags="-I${includedir}" gtest_cxxflags="@PTHREAD_CFLAGS@" fi # Do an installation query if requested. if test -n "$do_query"; then case $do_query in prefix) echo $prefix; exit 0;; exec-prefix) echo $exec_prefix; exit 0;; libdir) echo $libdir; exit 0;; includedir) echo $includedir; exit 0;; version) echo $version; exit 0;; *) show_usage; exit 1;; esac fi # Do a version check if requested. if test "$do_check_versions" = "yes"; then # Make sure we didn't receive a bad combination of parameters. test "$echo_cppflags" = "yes" && show_usage && exit 1 test "$echo_cxxflags" = "yes" && show_usage && exit 1 test "$echo_ldflags" = "yes" && show_usage && exit 1 test "$echo_libs" = "yes" && show_usage && exit 1 if test "$exact_version" != ""; then check_versions $exact_version $exact_version # unreachable else check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999} # unreachable fi fi # Do the output in the correct order so that these can be used in-line of # a compiler invocation. output="" test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags" test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags" test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags" test "$echo_libs" = "yes" && output="$output $gtest_libs" echo $output exit 0 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/pump.py000077500000000000000000000561711273231111400261260ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """pump v0.2.0 - Pretty Useful for Meta Programming. A tool for preprocessor meta programming. Useful for generating repetitive boilerplate code. Especially useful for writing C++ classes, functions, macros, and templates that need to work with various number of arguments. USAGE: pump.py SOURCE_FILE EXAMPLES: pump.py foo.cc.pump Converts foo.cc.pump to foo.cc. GRAMMAR: CODE ::= ATOMIC_CODE* ATOMIC_CODE ::= $var ID = EXPRESSION | $var ID = [[ CODE ]] | $range ID EXPRESSION..EXPRESSION | $for ID SEPARATOR [[ CODE ]] | $($) | $ID | $(EXPRESSION) | $if EXPRESSION [[ CODE ]] ELSE_BRANCH | [[ CODE ]] | RAW_CODE SEPARATOR ::= RAW_CODE | EMPTY ELSE_BRANCH ::= $else [[ CODE ]] | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH | EMPTY EXPRESSION has Python syntax. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys TOKEN_TABLE = [ (re.compile(r'\$var\s+'), '$var'), (re.compile(r'\$elif\s+'), '$elif'), (re.compile(r'\$else\s+'), '$else'), (re.compile(r'\$for\s+'), '$for'), (re.compile(r'\$if\s+'), '$if'), (re.compile(r'\$range\s+'), '$range'), (re.compile(r'\$[_A-Za-z]\w*'), '$id'), (re.compile(r'\$\(\$\)'), '$($)'), (re.compile(r'\$'), '$'), (re.compile(r'\[\[\n?'), '[['), (re.compile(r'\]\]\n?'), ']]'), ] class Cursor: """Represents a position (line and column) in a text file.""" def __init__(self, line=-1, column=-1): self.line = line self.column = column def __eq__(self, rhs): return self.line == rhs.line and self.column == rhs.column def __ne__(self, rhs): return not self == rhs def __lt__(self, rhs): return self.line < rhs.line or ( self.line == rhs.line and self.column < rhs.column) def __le__(self, rhs): return self < rhs or self == rhs def __gt__(self, rhs): return rhs < self def __ge__(self, rhs): return rhs <= self def __str__(self): if self == Eof(): return 'EOF' else: return '%s(%s)' % (self.line + 1, self.column) def __add__(self, offset): return Cursor(self.line, self.column + offset) def __sub__(self, offset): return Cursor(self.line, self.column - offset) def Clone(self): """Returns a copy of self.""" return Cursor(self.line, self.column) # Special cursor to indicate the end-of-file. def Eof(): """Returns the special cursor to denote the end-of-file.""" return Cursor(-1, -1) class Token: """Represents a token in a Pump source file.""" def __init__(self, start=None, end=None, value=None, token_type=None): if start is None: self.start = Eof() else: self.start = start if end is None: self.end = Eof() else: self.end = end self.value = value self.token_type = token_type def __str__(self): return 'Token @%s: \'%s\' type=%s' % ( self.start, self.value, self.token_type) def Clone(self): """Returns a copy of self.""" return Token(self.start.Clone(), self.end.Clone(), self.value, self.token_type) def StartsWith(lines, pos, string): """Returns True iff the given position in lines starts with 'string'.""" return lines[pos.line][pos.column:].startswith(string) def FindFirstInLine(line, token_table): best_match_start = -1 for (regex, token_type) in token_table: m = regex.search(line) if m: # We found regex in lines if best_match_start < 0 or m.start() < best_match_start: best_match_start = m.start() best_match_length = m.end() - m.start() best_match_token_type = token_type if best_match_start < 0: return None return (best_match_start, best_match_length, best_match_token_type) def FindFirst(lines, token_table, cursor): """Finds the first occurrence of any string in strings in lines.""" start = cursor.Clone() cur_line_number = cursor.line for line in lines[start.line:]: if cur_line_number == start.line: line = line[start.column:] m = FindFirstInLine(line, token_table) if m: # We found a regex in line. (start_column, length, token_type) = m if cur_line_number == start.line: start_column += start.column found_start = Cursor(cur_line_number, start_column) found_end = found_start + length return MakeToken(lines, found_start, found_end, token_type) cur_line_number += 1 # We failed to find str in lines return None def SubString(lines, start, end): """Returns a substring in lines.""" if end == Eof(): end = Cursor(len(lines) - 1, len(lines[-1])) if start >= end: return '' if start.line == end.line: return lines[start.line][start.column:end.column] result_lines = ([lines[start.line][start.column:]] + lines[start.line + 1:end.line] + [lines[end.line][:end.column]]) return ''.join(result_lines) def StripMetaComments(str): """Strip meta comments from each line in the given string.""" # First, completely remove lines containing nothing but a meta # comment, including the trailing \n. str = re.sub(r'^\s*\$\$.*\n', '', str) # Then, remove meta comments from contentful lines. return re.sub(r'\s*\$\$.*', '', str) def MakeToken(lines, start, end, token_type): """Creates a new instance of Token.""" return Token(start, end, SubString(lines, start, end), token_type) def ParseToken(lines, pos, regex, token_type): line = lines[pos.line][pos.column:] m = regex.search(line) if m and not m.start(): return MakeToken(lines, pos, pos + m.end(), token_type) else: print 'ERROR: %s expected at %s.' % (token_type, pos) sys.exit(1) ID_REGEX = re.compile(r'[_A-Za-z]\w*') EQ_REGEX = re.compile(r'=') REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)') OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*') WHITE_SPACE_REGEX = re.compile(r'\s') DOT_DOT_REGEX = re.compile(r'\.\.') def Skip(lines, pos, regex): line = lines[pos.line][pos.column:] m = re.search(regex, line) if m and not m.start(): return pos + m.end() else: return pos def SkipUntil(lines, pos, regex, token_type): line = lines[pos.line][pos.column:] m = re.search(regex, line) if m: return pos + m.start() else: print ('ERROR: %s expected on line %s after column %s.' % (token_type, pos.line + 1, pos.column)) sys.exit(1) def ParseExpTokenInParens(lines, pos): def ParseInParens(pos): pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX) pos = Skip(lines, pos, r'\(') pos = Parse(pos) pos = Skip(lines, pos, r'\)') return pos def Parse(pos): pos = SkipUntil(lines, pos, r'\(|\)', ')') if SubString(lines, pos, pos + 1) == '(': pos = Parse(pos + 1) pos = Skip(lines, pos, r'\)') return Parse(pos) else: return pos start = pos.Clone() pos = ParseInParens(pos) return MakeToken(lines, start, pos, 'exp') def RStripNewLineFromToken(token): if token.value.endswith('\n'): return Token(token.start, token.end, token.value[:-1], token.token_type) else: return token def TokenizeLines(lines, pos): while True: found = FindFirst(lines, TOKEN_TABLE, pos) if not found: yield MakeToken(lines, pos, Eof(), 'code') return if found.start == pos: prev_token = None prev_token_rstripped = None else: prev_token = MakeToken(lines, pos, found.start, 'code') prev_token_rstripped = RStripNewLineFromToken(prev_token) if found.token_type == '$var': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) eq_token = ParseToken(lines, pos, EQ_REGEX, '=') yield eq_token pos = Skip(lines, eq_token.end, r'\s*') if SubString(lines, pos, pos + 2) != '[[': exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp') yield exp_token pos = Cursor(exp_token.end.line + 1, 0) elif found.token_type == '$for': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX) elif found.token_type == '$range': if prev_token_rstripped: yield prev_token_rstripped yield found id_token = ParseToken(lines, found.end, ID_REGEX, 'id') yield id_token pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..') yield MakeToken(lines, pos, dots_pos, 'exp') yield MakeToken(lines, dots_pos, dots_pos + 2, '..') pos = dots_pos + 2 new_pos = Cursor(pos.line + 1, 0) yield MakeToken(lines, pos, new_pos, 'exp') pos = new_pos elif found.token_type == '$': if prev_token: yield prev_token yield found exp_token = ParseExpTokenInParens(lines, found.end) yield exp_token pos = exp_token.end elif (found.token_type == ']]' or found.token_type == '$if' or found.token_type == '$elif' or found.token_type == '$else'): if prev_token_rstripped: yield prev_token_rstripped yield found pos = found.end else: if prev_token: yield prev_token yield found pos = found.end def Tokenize(s): """A generator that yields the tokens in the given string.""" if s != '': lines = s.splitlines(True) for token in TokenizeLines(lines, Cursor(0, 0)): yield token class CodeNode: def __init__(self, atomic_code_list=None): self.atomic_code = atomic_code_list class VarNode: def __init__(self, identifier=None, atomic_code=None): self.identifier = identifier self.atomic_code = atomic_code class RangeNode: def __init__(self, identifier=None, exp1=None, exp2=None): self.identifier = identifier self.exp1 = exp1 self.exp2 = exp2 class ForNode: def __init__(self, identifier=None, sep=None, code=None): self.identifier = identifier self.sep = sep self.code = code class ElseNode: def __init__(self, else_branch=None): self.else_branch = else_branch class IfNode: def __init__(self, exp=None, then_branch=None, else_branch=None): self.exp = exp self.then_branch = then_branch self.else_branch = else_branch class RawCodeNode: def __init__(self, token=None): self.raw_code = token class LiteralDollarNode: def __init__(self, token): self.token = token class ExpNode: def __init__(self, token, python_exp): self.token = token self.python_exp = python_exp def PopFront(a_list): head = a_list[0] a_list[:1] = [] return head def PushFront(a_list, elem): a_list[:0] = [elem] def PopToken(a_list, token_type=None): token = PopFront(a_list) if token_type is not None and token.token_type != token_type: print 'ERROR: %s expected at %s' % (token_type, token.start) print 'ERROR: %s found instead' % (token,) sys.exit(1) return token def PeekToken(a_list): if not a_list: return None return a_list[0] def ParseExpNode(token): python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value) return ExpNode(token, python_exp) def ParseElseNode(tokens): def Pop(token_type=None): return PopToken(tokens, token_type) next = PeekToken(tokens) if not next: return None if next.token_type == '$else': Pop('$else') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return code_node elif next.token_type == '$elif': Pop('$elif') exp = Pop('code') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') inner_else_node = ParseElseNode(tokens) return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)]) elif not next.value.strip(): Pop('code') return ParseElseNode(tokens) else: return None def ParseAtomicCodeNode(tokens): def Pop(token_type=None): return PopToken(tokens, token_type) head = PopFront(tokens) t = head.token_type if t == 'code': return RawCodeNode(head) elif t == '$var': id_token = Pop('id') Pop('=') next = PeekToken(tokens) if next.token_type == 'exp': exp_token = Pop() return VarNode(id_token, ParseExpNode(exp_token)) Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return VarNode(id_token, code_node) elif t == '$for': id_token = Pop('id') next_token = PeekToken(tokens) if next_token.token_type == 'code': sep_token = next_token Pop('code') else: sep_token = None Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') return ForNode(id_token, sep_token, code_node) elif t == '$if': exp_token = Pop('code') Pop('[[') code_node = ParseCodeNode(tokens) Pop(']]') else_node = ParseElseNode(tokens) return IfNode(ParseExpNode(exp_token), code_node, else_node) elif t == '$range': id_token = Pop('id') exp1_token = Pop('exp') Pop('..') exp2_token = Pop('exp') return RangeNode(id_token, ParseExpNode(exp1_token), ParseExpNode(exp2_token)) elif t == '$id': return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id')) elif t == '$($)': return LiteralDollarNode(head) elif t == '$': exp_token = Pop('exp') return ParseExpNode(exp_token) elif t == '[[': code_node = ParseCodeNode(tokens) Pop(']]') return code_node else: PushFront(tokens, head) return None def ParseCodeNode(tokens): atomic_code_list = [] while True: if not tokens: break atomic_code_node = ParseAtomicCodeNode(tokens) if atomic_code_node: atomic_code_list.append(atomic_code_node) else: break return CodeNode(atomic_code_list) def ParseToAST(pump_src_text): """Convert the given Pump source text into an AST.""" tokens = list(Tokenize(pump_src_text)) code_node = ParseCodeNode(tokens) return code_node class Env: def __init__(self): self.variables = [] self.ranges = [] def Clone(self): clone = Env() clone.variables = self.variables[:] clone.ranges = self.ranges[:] return clone def PushVariable(self, var, value): # If value looks like an int, store it as an int. try: int_value = int(value) if ('%s' % int_value) == value: value = int_value except Exception: pass self.variables[:0] = [(var, value)] def PopVariable(self): self.variables[:1] = [] def PushRange(self, var, lower, upper): self.ranges[:0] = [(var, lower, upper)] def PopRange(self): self.ranges[:1] = [] def GetValue(self, identifier): for (var, value) in self.variables: if identifier == var: return value print 'ERROR: meta variable %s is undefined.' % (identifier,) sys.exit(1) def EvalExp(self, exp): try: result = eval(exp.python_exp) except Exception, e: print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e) print ('ERROR: failed to evaluate meta expression %s at %s' % (exp.python_exp, exp.token.start)) sys.exit(1) return result def GetRange(self, identifier): for (var, lower, upper) in self.ranges: if identifier == var: return (lower, upper) print 'ERROR: range %s is undefined.' % (identifier,) sys.exit(1) class Output: def __init__(self): self.string = '' def GetLastLine(self): index = self.string.rfind('\n') if index < 0: return '' return self.string[index + 1:] def Append(self, s): self.string += s def RunAtomicCode(env, node, output): if isinstance(node, VarNode): identifier = node.identifier.value.strip() result = Output() RunAtomicCode(env.Clone(), node.atomic_code, result) value = result.string env.PushVariable(identifier, value) elif isinstance(node, RangeNode): identifier = node.identifier.value.strip() lower = int(env.EvalExp(node.exp1)) upper = int(env.EvalExp(node.exp2)) env.PushRange(identifier, lower, upper) elif isinstance(node, ForNode): identifier = node.identifier.value.strip() if node.sep is None: sep = '' else: sep = node.sep.value (lower, upper) = env.GetRange(identifier) for i in range(lower, upper + 1): new_env = env.Clone() new_env.PushVariable(identifier, i) RunCode(new_env, node.code, output) if i != upper: output.Append(sep) elif isinstance(node, RawCodeNode): output.Append(node.raw_code.value) elif isinstance(node, IfNode): cond = env.EvalExp(node.exp) if cond: RunCode(env.Clone(), node.then_branch, output) elif node.else_branch is not None: RunCode(env.Clone(), node.else_branch, output) elif isinstance(node, ExpNode): value = env.EvalExp(node) output.Append('%s' % (value,)) elif isinstance(node, LiteralDollarNode): output.Append('$') elif isinstance(node, CodeNode): RunCode(env.Clone(), node, output) else: print 'BAD' print node sys.exit(1) def RunCode(env, code_node, output): for atomic_code in code_node.atomic_code: RunAtomicCode(env, atomic_code, output) def IsSingleLineComment(cur_line): return '//' in cur_line def IsInPreprocessorDirective(prev_lines, cur_line): if cur_line.lstrip().startswith('#'): return True return prev_lines and prev_lines[-1].endswith('\\') def WrapComment(line, output): loc = line.find('//') before_comment = line[:loc].rstrip() if before_comment == '': indent = loc else: output.append(before_comment) indent = len(before_comment) - len(before_comment.lstrip()) prefix = indent*' ' + '// ' max_len = 80 - len(prefix) comment = line[loc + 2:].strip() segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != ''] cur_line = '' for seg in segs: if len((cur_line + seg).rstrip()) < max_len: cur_line += seg else: if cur_line.strip() != '': output.append(prefix + cur_line.rstrip()) cur_line = seg.lstrip() if cur_line.strip() != '': output.append(prefix + cur_line.strip()) def WrapCode(line, line_concat, output): indent = len(line) - len(line.lstrip()) prefix = indent*' ' # Prefix of the current line max_len = 80 - indent - len(line_concat) # Maximum length of the current line new_prefix = prefix + 4*' ' # Prefix of a continuation line new_max_len = max_len - 4 # Maximum length of a continuation line # Prefers to wrap a line after a ',' or ';'. segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != ''] cur_line = '' # The current line without leading spaces. for seg in segs: # If the line is still too long, wrap at a space. while cur_line == '' and len(seg.strip()) > max_len: seg = seg.lstrip() split_at = seg.rfind(' ', 0, max_len) output.append(prefix + seg[:split_at].strip() + line_concat) seg = seg[split_at + 1:] prefix = new_prefix max_len = new_max_len if len((cur_line + seg).rstrip()) < max_len: cur_line = (cur_line + seg).lstrip() else: output.append(prefix + cur_line.rstrip() + line_concat) prefix = new_prefix max_len = new_max_len cur_line = seg.lstrip() if cur_line.strip() != '': output.append(prefix + cur_line.strip()) def WrapPreprocessorDirective(line, output): WrapCode(line, ' \\', output) def WrapPlainCode(line, output): WrapCode(line, '', output) def IsMultiLineIWYUPragma(line): return re.search(r'/\* IWYU pragma: ', line) def IsHeaderGuardIncludeOrOneLineIWYUPragma(line): return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or re.match(r'^#include\s', line) or # Don't break IWYU pragmas, either; that causes iwyu.py problems. re.search(r'// IWYU pragma: ', line)) def WrapLongLine(line, output): line = line.rstrip() if len(line) <= 80: output.append(line) elif IsSingleLineComment(line): if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): # The style guide made an exception to allow long header guard lines, # includes and IWYU pragmas. output.append(line) else: WrapComment(line, output) elif IsInPreprocessorDirective(output, line): if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): # The style guide made an exception to allow long header guard lines, # includes and IWYU pragmas. output.append(line) else: WrapPreprocessorDirective(line, output) elif IsMultiLineIWYUPragma(line): output.append(line) else: WrapPlainCode(line, output) def BeautifyCode(string): lines = string.splitlines() output = [] for line in lines: WrapLongLine(line, output) output2 = [line.rstrip() for line in output] return '\n'.join(output2) + '\n' def ConvertFromPumpSource(src_text): """Return the text generated from the given Pump source text.""" ast = ParseToAST(StripMetaComments(src_text)) output = Output() RunCode(Env(), ast, output) return BeautifyCode(output.string) def main(argv): if len(argv) == 1: print __doc__ sys.exit(1) file_path = argv[-1] output_str = ConvertFromPumpSource(file(file_path, 'r').read()) if file_path.endswith('.pump'): output_file_path = file_path[:-5] else: output_file_path = '-' if output_file_path == '-': print output_str, else: output_file = file(output_file_path, 'w') output_file.write('// This file was GENERATED by command:\n') output_file.write('// %s %s\n' % (os.path.basename(__file__), os.path.basename(file_path))) output_file.write('// DO NOT EDIT BY HAND!!!\n\n') output_file.write(output_str) output_file.close() if __name__ == '__main__': main(sys.argv) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/test/000077500000000000000000000000001273231111400255355ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/scripts/test/Makefile000066400000000000000000000034121273231111400271750ustar00rootroot00000000000000# A Makefile for fusing Google Test and building a sample test against it. # # SYNOPSIS: # # make [all] - makes everything. # make TARGET - makes the given target. # make check - makes everything and runs the built sample test. # make clean - removes all files generated by make. # Points to the root of fused Google Test, relative to where this file is. FUSED_GTEST_DIR = output # Paths to the fused gtest files. FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc # Where to find the sample test. SAMPLE_DIR = ../../samples # Where to find gtest_main.cc. GTEST_MAIN_CC = ../../src/gtest_main.cc # Flags passed to the preprocessor. # We have no idea here whether pthreads is available in the system, so # disable its use. CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0 # Flags passed to the C++ compiler. CXXFLAGS += -g all : sample1_unittest check : all ./sample1_unittest clean : rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o $(FUSED_GTEST_H) : ../fuse_gtest_files.py $(FUSED_GTEST_DIR) $(FUSED_GTEST_ALL_CC) : ../fuse_gtest_files.py $(FUSED_GTEST_DIR) gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC) sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \ $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/000077500000000000000000000000001273231111400236565ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-all.cc000066400000000000000000000041611273231111400260630ustar00rootroot00000000000000// 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" mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-death-test.cc000066400000000000000000001434051273231111400273620ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #include "gtest/gtest-death-test.h" #include "gtest/internal/gtest-port.h" #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.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 { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "the '|' characters. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. static bool g_in_fast_death_test_child = false; // 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. bool InDeathTestChild() { # if GTEST_OS_WINDOWS // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { # if GTEST_OS_WINDOWS return exit_status == exit_code_; # else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; # endif // GTEST_OS_WINDOWS } # if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; # else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } # ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } # endif # endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } # if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } # endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. // TODO(vladl@google.com): Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); posix::Abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. # define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestThrew: set_outcome(THREW); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, THREW, or RETURNED. The death test // fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const std::string error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } # if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } # else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); return args; } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; # if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } # else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC # if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } # else const bool use_fork = true; # endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, NULL)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } # endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } # if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } # endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; # if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); # else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-filepath.cc000066400000000000000000000336361273231111400271200ustar00rootroot00000000000000// 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 #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // 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_.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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-internal-inl.h000066400000000000000000001326011273231111400275520ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #include "gtest/internal/gtest-port.h" #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS #include "gtest/gtest.h" // NOLINT #include "gtest/gtest-spi.h" namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const std::string &test_case_name, const std::string &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual string CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test case, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. GTEST_API_ std::string GetLastErrnoDescription(); # if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; # endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. # if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); # else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); # endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } virtual ~SocketWriter() { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. virtual void Send(const string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const int len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != len) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const string host_name_; const string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static string UrlEncode(const char* str); StreamingListener(const string& host, const string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-port.cc000066400000000000000000000655121273231111400263060ustar00rootroot00000000000000// 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 #include #include #include #if GTEST_OS_WINDOWS_MOBILE # include // For TerminateProcess() #elif GTEST_OS_WINDOWS # include # include #else # include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include #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(thread_list), sizeof(thread_t) * thread_count); return static_cast(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(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(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 , 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(-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(pattern_)); free(const_cast(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(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(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 g_argvs; static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& 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(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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-printers.cc000066400000000000000000000277631273231111400271760ustar00rootroot00000000000000// 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::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 #include #include // NOLINT #include #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 static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(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(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(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(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(static_cast(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 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(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(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(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(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(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 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 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_(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_(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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-test-part.cc000066400000000000000000000100771273231111400272410ustar00rootroot00000000000000// 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(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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest-typed-test.cc000066400000000000000000000072621273231111400274220ustar00rootroot00000000000000// 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_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 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 mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest.cc000066400000000000000000005475161273231111400253350ustar00rootroot00000000000000// 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) #include "gtest/gtest.h" #include "gtest/gtest-spi.h" #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal static const char* GetDefaultFilter() { return kUniversalFilter; } GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. GTEST_API_ int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. std::string g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter( const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const std::string &test_name) { const std::string& full_name = test_case_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); std::string positive; std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == NULL) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const string& substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return ""; } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; # ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); # pragma warning(pop) // Restores the warning state. # else _ftime64(&now); # endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." #endif } // Utilities // class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& Message::operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new ::std::string(*other.message_) : static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; # else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } # endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, Mac OS X and Cygwin don't define wcscasecmp. // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Returns true iff str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } bool ValidateTestPropertyName(const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, ""); // No stack trace, either. } } // namespace internal // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const TestInfo* const first_test_info = test_case->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. const TestInfo* const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(NULL, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } private: std::string name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test only if the test object was created and its // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. int TestCase::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestCase::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // a_type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static std::string FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // Text printed in Google Test's text output and --gunit_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { printf("%s = %s", kValueParamLabel, value_param); } } } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == NULL) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_info.test_case_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(::std::ostream* stream, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } break; } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms/1000.0; return ss.str(); } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { // Using non-reentrant version as localtime_r is not portable. time_t seconds = static_cast(ms / 1000); #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function or variable may be unsafe). const struct tm* const time_struct = localtime(&seconds); // NOLINT # pragma warning(pop) // Restores the warning state again. #else const struct tm* const time_struct = localtime(&seconds); // NOLINT #endif if (time_struct == NULL) return ""; // Invalid ms value // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct->tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct->tm_mday) + "T" + String::FormatIntWidth2(time_struct->tm_hour) + ":" + String::FormatIntWidth2(time_struct->tm_min) + ":" + String::FormatIntWidth2(time_struct->tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; *stream << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, const TestCase& test_case) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { if (unit_test.GetTestCase(i)->reportable_test_count() > 0) PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. string StreamingListener::UrlEncode(const char* str) { string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = NULL; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, int /* skip_count */) GTEST_LOCK_EXCLUDED_(mutex_) { return ""; } void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath) { // If a path to the premature-exit file is specified... if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { remove(premature_exit_filepath_); } } private: const char* const premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: Symbian doesn't implement abort() well, and some debuggers // don't correctly trap abort(). *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); # endif // !GTEST_OS_WINDOWS_MOBILE # if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); # endif # if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } #endif // GTEST_HAS_SEH return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), # pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test case's ad_hoc_test_result when invoke // from SetUpTestCase/TearDownTestCase, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != NULL) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_case_ != NULL) { xml_element = "testsuite"; test_result = &(current_test_case_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", target.c_str()); fflush(stdout); } } } #endif // GTEST_CAN_STREAM_RESULTS_ // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const std::string& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: std::string name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(test_case_name, kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return false; } // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return true; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const std::string &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const std::string test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != NULL) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.", test_case->name()); if (test_case->type_param() != NULL) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != NULL) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? &(current_test_info_->result_) : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" #endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/src/gtest_main.cc000066400000000000000000000033451273231111400263240ustar00rootroot00000000000000// 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 #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(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/000077500000000000000000000000001273231111400240465ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-death-test_ex_test.cc000066400000000000000000000071371273231111400313060ustar00rootroot00000000000000// Copyright 2010, 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) // // Tests that verify interaction of exceptions and death tests. #include "gtest/gtest-death-test.h" #include "gtest/gtest.h" #if GTEST_HAS_DEATH_TEST # if GTEST_HAS_SEH # include // For RaiseException(). # endif # include "gtest/gtest-spi.h" # if GTEST_HAS_EXCEPTIONS # include // For std::exception. // Tests that death tests report thrown exceptions as failures and that the // exceptions do not escape death test macros. TEST(CxxExceptionDeathTest, ExceptionIsFailure) { try { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception"); } catch (...) { // NOLINT FAIL() << "An exception escaped a death test macro invocation " << "with catch_exceptions " << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); } } class TestException : public std::exception { public: virtual const char* what() const throw() { return "exceptional message"; } }; TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) { // Verifies that the exception message is quoted in the failure text. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), "exceptional message"); // Verifies that the location is mentioned in the failure text. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), "gtest-death-test_ex_test.cc"); } # endif // GTEST_HAS_EXCEPTIONS # if GTEST_HAS_SEH // Tests that enabling interception of SEH exceptions with the // catch_exceptions flag does not interfere with SEH exceptions being // treated as death by death tests. TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) { EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "") << "with catch_exceptions " << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); } # endif #endif // GTEST_HAS_DEATH_TEST int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0; return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-death-test_test.cc000066400000000000000000001243441273231111400306120ustar00rootroot00000000000000// 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) // // Tests for death tests. #include "gtest/gtest-death-test.h" #include "gtest/gtest.h" #include "gtest/internal/gtest-filepath.h" using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; #if GTEST_HAS_DEATH_TEST # if GTEST_OS_WINDOWS # include // For chdir(). # else # include # include // For waitpid. # endif // GTEST_OS_WINDOWS # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include "gtest/gtest-spi.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 posix = ::testing::internal::posix; using testing::Message; using testing::internal::DeathTest; using testing::internal::DeathTestFactory; using testing::internal::FilePath; using testing::internal::GetLastErrnoDescription; using testing::internal::GetUnitTestImpl; using testing::internal::InDeathTestChild; using testing::internal::ParseNaturalNumber; namespace testing { namespace internal { // A helper class whose objects replace the death test factory for a // single UnitTest object during their lifetimes. class ReplaceDeathTestFactory { public: explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory) : unit_test_impl_(GetUnitTestImpl()) { old_factory_ = unit_test_impl_->death_test_factory_.release(); unit_test_impl_->death_test_factory_.reset(new_factory); } ~ReplaceDeathTestFactory() { unit_test_impl_->death_test_factory_.release(); unit_test_impl_->death_test_factory_.reset(old_factory_); } private: // Prevents copying ReplaceDeathTestFactory objects. ReplaceDeathTestFactory(const ReplaceDeathTestFactory&); void operator=(const ReplaceDeathTestFactory&); UnitTestImpl* unit_test_impl_; DeathTestFactory* old_factory_; }; } // namespace internal } // namespace testing void DieWithMessage(const ::std::string& message) { fprintf(stderr, "%s", message.c_str()); fflush(stderr); // Make sure the text is printed before the process exits. // We call _exit() instead of exit(), as the former is a direct // system call and thus safer in the presence of threads. exit() // will invoke user-defined exit-hooks, which may do dangerous // things that conflict with death tests. // // Some compilers can recognize that _exit() never returns and issue the // 'unreachable code' warning for code following this function, unless // fooled by a fake condition. if (AlwaysTrue()) _exit(1); } void DieInside(const ::std::string& function) { DieWithMessage("death inside " + function + "()."); } // Tests that death tests work. class TestForDeathTest : public testing::Test { protected: TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} virtual ~TestForDeathTest() { posix::ChDir(original_dir_.c_str()); } // A static member function that's expected to die. static void StaticMemberFunction() { DieInside("StaticMemberFunction"); } // A method of the test fixture that may die. void MemberFunction() { if (should_die_) DieInside("MemberFunction"); } // True iff MemberFunction() should die. bool should_die_; const FilePath original_dir_; }; // A class with a member function that may die. class MayDie { public: explicit MayDie(bool should_die) : should_die_(should_die) {} // A member function that may die. void MemberFunction() const { if (should_die_) DieInside("MayDie::MemberFunction"); } private: // True iff MemberFunction() should die. bool should_die_; }; // A global function that's expected to die. void GlobalFunction() { DieInside("GlobalFunction"); } // A non-void function that's expected to die. int NonVoidFunction() { DieInside("NonVoidFunction"); return 1; } // A unary function that may die. void DieIf(bool should_die) { if (should_die) DieInside("DieIf"); } // A binary function that may die. bool DieIfLessThan(int x, int y) { if (x < y) { DieInside("DieIfLessThan"); } return true; } // Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. void DeathTestSubroutine() { EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction"); ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction"); } // Death in dbg, not opt. int DieInDebugElse12(int* sideeffect) { if (sideeffect) *sideeffect = 12; # ifndef NDEBUG DieInside("DieInDebugElse12"); # endif // NDEBUG return 12; } # if GTEST_OS_WINDOWS // Tests the ExitedWithCode predicate. TEST(ExitStatusPredicateTest, ExitedWithCode) { // On Windows, the process's exit code is the same as its exit status, // so the predicate just compares the its input with its parameter. EXPECT_TRUE(testing::ExitedWithCode(0)(0)); EXPECT_TRUE(testing::ExitedWithCode(1)(1)); EXPECT_TRUE(testing::ExitedWithCode(42)(42)); EXPECT_FALSE(testing::ExitedWithCode(0)(1)); EXPECT_FALSE(testing::ExitedWithCode(1)(0)); } # else // Returns the exit status of a process that calls _exit(2) with a // given exit code. This is a helper function for the // ExitStatusPredicateTest test suite. static int NormalExitStatus(int exit_code) { pid_t child_pid = fork(); if (child_pid == 0) { _exit(exit_code); } int status; waitpid(child_pid, &status, 0); return status; } // Returns the exit status of a process that raises a given signal. // If the signal does not cause the process to die, then it returns // instead the exit status of a process that exits normally with exit // code 1. This is a helper function for the ExitStatusPredicateTest // test suite. static int KilledExitStatus(int signum) { pid_t child_pid = fork(); if (child_pid == 0) { raise(signum); _exit(1); } int status; waitpid(child_pid, &status, 0); return status; } // Tests the ExitedWithCode predicate. TEST(ExitStatusPredicateTest, ExitedWithCode) { const int status0 = NormalExitStatus(0); const int status1 = NormalExitStatus(1); const int status42 = NormalExitStatus(42); const testing::ExitedWithCode pred0(0); const testing::ExitedWithCode pred1(1); const testing::ExitedWithCode pred42(42); EXPECT_PRED1(pred0, status0); EXPECT_PRED1(pred1, status1); EXPECT_PRED1(pred42, status42); EXPECT_FALSE(pred0(status1)); EXPECT_FALSE(pred42(status0)); EXPECT_FALSE(pred1(status42)); } // Tests the KilledBySignal predicate. TEST(ExitStatusPredicateTest, KilledBySignal) { const int status_segv = KilledExitStatus(SIGSEGV); const int status_kill = KilledExitStatus(SIGKILL); const testing::KilledBySignal pred_segv(SIGSEGV); const testing::KilledBySignal pred_kill(SIGKILL); EXPECT_PRED1(pred_segv, status_segv); EXPECT_PRED1(pred_kill, status_kill); EXPECT_FALSE(pred_segv(status_kill)); EXPECT_FALSE(pred_kill(status_segv)); } # endif // GTEST_OS_WINDOWS // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. TEST_F(TestForDeathTest, SingleStatement) { if (AlwaysFalse()) // This would fail if executed; this is a compilation test only ASSERT_DEATH(return, ""); if (AlwaysTrue()) EXPECT_DEATH(_exit(1), ""); else // This empty "else" branch is meant to ensure that EXPECT_DEATH // doesn't expand into an "if" statement without an "else" ; if (AlwaysFalse()) ASSERT_DEATH(return, "") << "did not die"; if (AlwaysFalse()) ; else EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; } void DieWithEmbeddedNul() { fprintf(stderr, "Hello%cmy null world.\n", '\0'); fflush(stderr); _exit(1); } # if GTEST_USES_PCRE // Tests that EXPECT_DEATH and ASSERT_DEATH work when the error // message has a NUL character in it. TEST_F(TestForDeathTest, EmbeddedNulInMessage) { // TODO(wan@google.com): doesn't support matching strings // with embedded NUL characters - find a way to workaround it. EXPECT_DEATH(DieWithEmbeddedNul(), "my null world"); ASSERT_DEATH(DieWithEmbeddedNul(), "my null world"); } # endif // GTEST_USES_PCRE // Tests that death test macros expand to code which interacts well with switch // statements. TEST_F(TestForDeathTest, SwitchStatement) { // Microsoft compiler usually complains about switch statements without // case labels. We suppress that warning for this test. # ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4065) # endif // _MSC_VER switch (0) default: ASSERT_DEATH(_exit(1), "") << "exit in default switch handler"; switch (0) case 0: EXPECT_DEATH(_exit(1), "") << "exit in switch case"; # ifdef _MSC_VER # pragma warning(pop) # endif // _MSC_VER } // Tests that a static member function can be used in a "fast" style // death test. TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); } // Tests that a method of the test fixture can be used in a "fast" // style death test. TEST_F(TestForDeathTest, MemberFunctionFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; should_die_ = true; EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); } void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); } // Tests that death tests work even if the current directory has been // changed. TEST_F(TestForDeathTest, FastDeathTestInChangedDir) { testing::GTEST_FLAG(death_test_style) = "fast"; ChangeToRootDir(); EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ChangeToRootDir(); ASSERT_DEATH(_exit(1), ""); } # if GTEST_OS_LINUX void SigprofAction(int, siginfo_t*, void*) { /* no op */ } // Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms). void SetSigprofActionAndTimer() { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 1; timer.it_value = timer.it_interval; ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL)); struct sigaction signal_action; memset(&signal_action, 0, sizeof(signal_action)); sigemptyset(&signal_action.sa_mask); signal_action.sa_sigaction = SigprofAction; signal_action.sa_flags = SA_RESTART | SA_SIGINFO; ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, NULL)); } // Disables ITIMER_PROF timer and ignores SIGPROF signal. void DisableSigprofActionAndTimer(struct sigaction* old_signal_action) { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value = timer.it_interval; ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL)); struct sigaction signal_action; memset(&signal_action, 0, sizeof(signal_action)); sigemptyset(&signal_action.sa_mask); signal_action.sa_handler = SIG_IGN; ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action)); } // Tests that death tests work when SIGPROF handler and timer are set. TEST_F(TestForDeathTest, FastSigprofActionSet) { testing::GTEST_FLAG(death_test_style) = "fast"; SetSigprofActionAndTimer(); EXPECT_DEATH(_exit(1), ""); struct sigaction old_signal_action; DisableSigprofActionAndTimer(&old_signal_action); EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); } TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; SetSigprofActionAndTimer(); EXPECT_DEATH(_exit(1), ""); struct sigaction old_signal_action; DisableSigprofActionAndTimer(&old_signal_action); EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); } # endif // GTEST_OS_LINUX // Repeats a representative sample of death tests in the "threadsafe" style: TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); } TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; should_die_ = true; EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); } TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; for (int i = 0; i < 3; ++i) EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i; } TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; ChangeToRootDir(); EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ChangeToRootDir(); ASSERT_DEATH(_exit(1), ""); } TEST_F(TestForDeathTest, MixedStyles) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_DEATH(_exit(1), ""); testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH(_exit(1), ""); } # if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD namespace { bool pthread_flag; void SetPthreadFlag() { pthread_flag = true; } } // namespace TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { if (!testing::GTEST_FLAG(death_test_use_fork)) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; pthread_flag = false; ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL)); ASSERT_DEATH(_exit(1), ""); ASSERT_FALSE(pthread_flag); } } # endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD // Tests that a method of another class can be used in a death test. TEST_F(TestForDeathTest, MethodOfAnotherClass) { const MayDie x(true); ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction"); } // Tests that a global function can be used in a death test. TEST_F(TestForDeathTest, GlobalFunction) { EXPECT_DEATH(GlobalFunction(), "GlobalFunction"); } // Tests that any value convertible to an RE works as a second // argument to EXPECT_DEATH. TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE) { static const char regex_c_str[] = "GlobalFunction"; EXPECT_DEATH(GlobalFunction(), regex_c_str); const testing::internal::RE regex(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex); # if GTEST_HAS_GLOBAL_STRING const string regex_str(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex_str); # endif // GTEST_HAS_GLOBAL_STRING const ::std::string regex_std_str(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex_std_str); } // Tests that a non-void function can be used in a death test. TEST_F(TestForDeathTest, NonVoidFunction) { ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction"); } // Tests that functions that take parameter(s) can be used in a death test. TEST_F(TestForDeathTest, FunctionWithParameter) { EXPECT_DEATH(DieIf(true), "DieIf\\(\\)"); EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan"); } // Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. TEST_F(TestForDeathTest, OutsideFixture) { DeathTestSubroutine(); } // Tests that death tests can be done inside a loop. TEST_F(TestForDeathTest, InsideLoop) { for (int i = 0; i < 5; i++) { EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i; } } // Tests that a compound statement can be used in a death test. TEST_F(TestForDeathTest, CompoundStatement) { EXPECT_DEATH({ // NOLINT const int x = 2; const int y = x + 1; DieIfLessThan(x, y); }, "DieIfLessThan"); } // Tests that code that doesn't die causes a death test to fail. TEST_F(TestForDeathTest, DoesNotDie) { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"), "failed to die"); } // Tests that a death test fails when the error message isn't expected. TEST_F(TestForDeathTest, ErrorMessageMismatch) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message."; }, "died but not with expected error"); } // On exit, *aborted will be true iff the EXPECT_DEATH() statement // aborted the function. void ExpectDeathTestHelper(bool* aborted) { *aborted = true; EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. *aborted = false; } // Tests that EXPECT_DEATH doesn't abort the test on failure. TEST_F(TestForDeathTest, EXPECT_DEATH) { bool aborted = true; EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted), "failed to die"); EXPECT_FALSE(aborted); } // Tests that ASSERT_DEATH does abort the test on failure. TEST_F(TestForDeathTest, ASSERT_DEATH) { static bool aborted; EXPECT_FATAL_FAILURE({ // NOLINT aborted = true; ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. aborted = false; }, "failed to die"); EXPECT_TRUE(aborted); } // Tests that EXPECT_DEATH evaluates the arguments exactly once. TEST_F(TestForDeathTest, SingleEvaluation) { int x = 3; EXPECT_DEATH(DieIf((++x) == 4), "DieIf"); const char* regex = "DieIf"; const char* regex_save = regex; EXPECT_DEATH(DieIfLessThan(3, 4), regex++); EXPECT_EQ(regex_save + 1, regex); } // Tests that run-away death tests are reported as failures. TEST_F(TestForDeathTest, RunawayIsFailure) { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast(0), "Foo"), "failed to die."); } // Tests that death tests report executing 'return' in the statement as // failure. TEST_F(TestForDeathTest, ReturnIsFailure) { EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"), "illegal return in test statement."); } // Tests that EXPECT_DEBUG_DEATH works as expected, that is, you can stream a // message to it, and in debug mode it: // 1. Asserts on death. // 2. Has no side effect. // // And in opt mode, it: // 1. Has side effects but does not assert. TEST_F(TestForDeathTest, TestExpectDebugDeath) { int sideeffect = 0; EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12") << "Must accept a streamed message"; # ifdef NDEBUG // Checks that the assignment occurs in opt mode (sideeffect). EXPECT_EQ(12, sideeffect); # else // Checks that the assignment does not occur in dbg mode (no sideeffect). EXPECT_EQ(0, sideeffect); # endif } // Tests that ASSERT_DEBUG_DEATH works as expected, that is, you can stream a // message to it, and in debug mode it: // 1. Asserts on death. // 2. Has no side effect. // // And in opt mode, it: // 1. Has side effects but does not assert. TEST_F(TestForDeathTest, TestAssertDebugDeath) { int sideeffect = 0; ASSERT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12") << "Must accept a streamed message"; # ifdef NDEBUG // Checks that the assignment occurs in opt mode (sideeffect). EXPECT_EQ(12, sideeffect); # else // Checks that the assignment does not occur in dbg mode (no sideeffect). EXPECT_EQ(0, sideeffect); # endif } # ifndef NDEBUG void ExpectDebugDeathHelper(bool* aborted) { *aborted = true; EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail."; *aborted = false; } # if GTEST_OS_WINDOWS TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort) { printf("This test should be considered failing if it shows " "any pop-up dialogs.\n"); fflush(stdout); EXPECT_DEATH({ testing::GTEST_FLAG(catch_exceptions) = false; abort(); }, ""); } # endif // GTEST_OS_WINDOWS // Tests that EXPECT_DEBUG_DEATH in debug mode does not abort // the function. TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) { bool aborted = true; EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), ""); EXPECT_FALSE(aborted); } void AssertDebugDeathHelper(bool* aborted) { *aborted = true; ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail."; *aborted = false; } // Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on // failure. TEST_F(TestForDeathTest, AssertDebugDeathAborts) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } # endif // _NDEBUG // Tests the *_EXIT family of macros, using a variety of predicates. static void TestExitMacros() { EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); # if GTEST_OS_WINDOWS // Of all signals effects on the process exit code, only those of SIGABRT // are documented on Windows. // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx. EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), "") << "b_ar"; # else EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo"; ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar"; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "") << "This failure is expected, too."; }, "This failure is expected, too."); # endif // GTEST_OS_WINDOWS EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "") << "This failure is expected."; }, "This failure is expected."); } TEST_F(TestForDeathTest, ExitMacros) { TestExitMacros(); } TEST_F(TestForDeathTest, ExitMacrosUsingFork) { testing::GTEST_FLAG(death_test_use_fork) = true; TestExitMacros(); } TEST_F(TestForDeathTest, InvalidStyle) { testing::GTEST_FLAG(death_test_style) = "rococo"; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(_exit(0), "") << "This failure is expected."; }, "This failure is expected."); } TEST_F(TestForDeathTest, DeathTestFailedOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH(DieWithMessage("death\n"), "expected message"), "Actual msg:\n" "[ DEATH ] death\n"); } TEST_F(TestForDeathTest, DeathTestUnexpectedReturnOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH({ fprintf(stderr, "returning\n"); fflush(stderr); return; }, ""), " Result: illegal return in test statement.\n" " Error msg:\n" "[ DEATH ] returning\n"); } TEST_F(TestForDeathTest, DeathTestBadExitCodeOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_EXIT(DieWithMessage("exiting with rc 1\n"), testing::ExitedWithCode(3), "expected message"), " Result: died but not with expected exit code:\n" " Exited with exit status 1\n" "Actual msg:\n" "[ DEATH ] exiting with rc 1\n"); } TEST_F(TestForDeathTest, DeathTestMultiLineMatchFail) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), "line 1\nxyz\nline 3\n"), "Actual msg:\n" "[ DEATH ] line 1\n" "[ DEATH ] line 2\n" "[ DEATH ] line 3\n"); } TEST_F(TestForDeathTest, DeathTestMultiLineMatchPass) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), "line 1\nline 2\nline 3\n"); } // A DeathTestFactory that returns MockDeathTests. class MockDeathTestFactory : public DeathTestFactory { public: MockDeathTestFactory(); virtual bool Create(const char* statement, const ::testing::internal::RE* regex, const char* file, int line, DeathTest** test); // Sets the parameters for subsequent calls to Create. void SetParameters(bool create, DeathTest::TestRole role, int status, bool passed); // Accessors. int AssumeRoleCalls() const { return assume_role_calls_; } int WaitCalls() const { return wait_calls_; } int PassedCalls() const { return passed_args_.size(); } bool PassedArgument(int n) const { return passed_args_[n]; } int AbortCalls() const { return abort_args_.size(); } DeathTest::AbortReason AbortArgument(int n) const { return abort_args_[n]; } bool TestDeleted() const { return test_deleted_; } private: friend class MockDeathTest; // If true, Create will return a MockDeathTest; otherwise it returns // NULL. bool create_; // The value a MockDeathTest will return from its AssumeRole method. DeathTest::TestRole role_; // The value a MockDeathTest will return from its Wait method. int status_; // The value a MockDeathTest will return from its Passed method. bool passed_; // Number of times AssumeRole was called. int assume_role_calls_; // Number of times Wait was called. int wait_calls_; // The arguments to the calls to Passed since the last call to // SetParameters. std::vector passed_args_; // The arguments to the calls to Abort since the last call to // SetParameters. std::vector abort_args_; // True if the last MockDeathTest returned by Create has been // deleted. bool test_deleted_; }; // A DeathTest implementation useful in testing. It returns values set // at its creation from its various inherited DeathTest methods, and // reports calls to those methods to its parent MockDeathTestFactory // object. class MockDeathTest : public DeathTest { public: MockDeathTest(MockDeathTestFactory *parent, TestRole role, int status, bool passed) : parent_(parent), role_(role), status_(status), passed_(passed) { } virtual ~MockDeathTest() { parent_->test_deleted_ = true; } virtual TestRole AssumeRole() { ++parent_->assume_role_calls_; return role_; } virtual int Wait() { ++parent_->wait_calls_; return status_; } virtual bool Passed(bool exit_status_ok) { parent_->passed_args_.push_back(exit_status_ok); return passed_; } virtual void Abort(AbortReason reason) { parent_->abort_args_.push_back(reason); } private: MockDeathTestFactory* const parent_; const TestRole role_; const int status_; const bool passed_; }; // MockDeathTestFactory constructor. MockDeathTestFactory::MockDeathTestFactory() : create_(true), role_(DeathTest::OVERSEE_TEST), status_(0), passed_(true), assume_role_calls_(0), wait_calls_(0), passed_args_(), abort_args_() { } // Sets the parameters for subsequent calls to Create. void MockDeathTestFactory::SetParameters(bool create, DeathTest::TestRole role, int status, bool passed) { create_ = create; role_ = role; status_ = status; passed_ = passed; assume_role_calls_ = 0; wait_calls_ = 0; passed_args_.clear(); abort_args_.clear(); } // Sets test to NULL (if create_ is false) or to the address of a new // MockDeathTest object with parameters taken from the last call // to SetParameters (if create_ is true). Always returns true. bool MockDeathTestFactory::Create(const char* /*statement*/, const ::testing::internal::RE* /*regex*/, const char* /*file*/, int /*line*/, DeathTest** test) { test_deleted_ = false; if (create_) { *test = new MockDeathTest(this, role_, status_, passed_); } else { *test = NULL; } return true; } // A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro. // It installs a MockDeathTestFactory that is used for the duration // of the test case. class MacroLogicDeathTest : public testing::Test { protected: static testing::internal::ReplaceDeathTestFactory* replacer_; static MockDeathTestFactory* factory_; static void SetUpTestCase() { factory_ = new MockDeathTestFactory; replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_); } static void TearDownTestCase() { delete replacer_; replacer_ = NULL; delete factory_; factory_ = NULL; } // Runs a death test that breaks the rules by returning. Such a death // test cannot be run directly from a test routine that uses a // MockDeathTest, or the remainder of the routine will not be executed. static void RunReturningDeathTest(bool* flag) { ASSERT_DEATH({ // NOLINT *flag = true; return; }, ""); } }; testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_ = NULL; MockDeathTestFactory* MacroLogicDeathTest::factory_ = NULL; // Test that nothing happens when the factory doesn't return a DeathTest: TEST_F(MacroLogicDeathTest, NothingHappens) { bool flag = false; factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(0, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_FALSE(factory_->TestDeleted()); } // Test that the parent process doesn't run the death test code, // and that the Passed method returns false when the (simulated) // child process exits with status 0: TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully) { bool flag = false; factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(1, factory_->WaitCalls()); ASSERT_EQ(1, factory_->PassedCalls()); EXPECT_FALSE(factory_->PassedArgument(0)); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the Passed method was given the argument "true" when // the (simulated) child process exits with status 1: TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully) { bool flag = false; factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true); EXPECT_DEATH(flag = true, ""); EXPECT_FALSE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(1, factory_->WaitCalls()); ASSERT_EQ(1, factory_->PassedCalls()); EXPECT_TRUE(factory_->PassedArgument(0)); EXPECT_EQ(0, factory_->AbortCalls()); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the (simulated) child process executes the death test // code, and is aborted with the correct AbortReason if it // executes a return statement. TEST_F(MacroLogicDeathTest, ChildPerformsReturn) { bool flag = false; factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); RunReturningDeathTest(&flag); EXPECT_TRUE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); EXPECT_EQ(1, factory_->AbortCalls()); EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, factory_->AbortArgument(0)); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that the (simulated) child process is aborted with the // correct AbortReason if it does not die. TEST_F(MacroLogicDeathTest, ChildDoesNotDie) { bool flag = false; factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); EXPECT_DEATH(flag = true, ""); EXPECT_TRUE(flag); EXPECT_EQ(1, factory_->AssumeRoleCalls()); EXPECT_EQ(0, factory_->WaitCalls()); EXPECT_EQ(0, factory_->PassedCalls()); // This time there are two calls to Abort: one since the test didn't // die, and another from the ReturnSentinel when it's destroyed. The // sentinel normally isn't destroyed if a test doesn't die, since // _exit(2) is called in that case by ForkingDeathTest, but not by // our MockDeathTest. ASSERT_EQ(2, factory_->AbortCalls()); EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE, factory_->AbortArgument(0)); EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, factory_->AbortArgument(1)); EXPECT_TRUE(factory_->TestDeleted()); } // Tests that a successful death test does not register a successful // test part. TEST(SuccessRegistrationDeathTest, NoSuccessPart) { EXPECT_DEATH(_exit(1), ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } TEST(StreamingAssertionsDeathTest, DeathTest) { EXPECT_DEATH(_exit(1), "") << "unexpected failure"; ASSERT_DEATH(_exit(1), "") << "unexpected failure"; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_DEATH(_exit(0), "") << "expected failure"; }, "expected failure"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_DEATH(_exit(0), "") << "expected failure"; }, "expected failure"); } // Tests that GetLastErrnoDescription returns an empty string when the // last error is 0 and non-empty string when it is non-zero. TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) { errno = ENOENT; EXPECT_STRNE("", GetLastErrnoDescription().c_str()); errno = 0; EXPECT_STREQ("", GetLastErrnoDescription().c_str()); } # if GTEST_OS_WINDOWS TEST(AutoHandleTest, AutoHandleWorks) { HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); ASSERT_NE(INVALID_HANDLE_VALUE, handle); // Tests that the AutoHandle is correctly initialized with a handle. testing::internal::AutoHandle auto_handle(handle); EXPECT_EQ(handle, auto_handle.Get()); // Tests that Reset assigns INVALID_HANDLE_VALUE. // Note that this cannot verify whether the original handle is closed. auto_handle.Reset(); EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get()); // Tests that Reset assigns the new handle. // Note that this cannot verify whether the original handle is closed. handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); ASSERT_NE(INVALID_HANDLE_VALUE, handle); auto_handle.Reset(handle); EXPECT_EQ(handle, auto_handle.Get()); // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default. testing::internal::AutoHandle auto_handle2; EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get()); } # endif // GTEST_OS_WINDOWS # if GTEST_OS_WINDOWS typedef unsigned __int64 BiggestParsable; typedef signed __int64 BiggestSignedParsable; # else typedef unsigned long long BiggestParsable; typedef signed long long BiggestSignedParsable; # endif // GTEST_OS_WINDOWS // We cannot use std::numeric_limits::max() as it clashes with the // max() macro defined by . const BiggestParsable kBiggestParsableMax = ULLONG_MAX; const BiggestSignedParsable kBiggestSignedParsableMax = LLONG_MAX; TEST(ParseNaturalNumberTest, RejectsInvalidFormat) { BiggestParsable result = 0; // Rejects non-numbers. EXPECT_FALSE(ParseNaturalNumber("non-number string", &result)); // Rejects numbers with whitespace prefix. EXPECT_FALSE(ParseNaturalNumber(" 123", &result)); // Rejects negative numbers. EXPECT_FALSE(ParseNaturalNumber("-123", &result)); // Rejects numbers starting with a plus sign. EXPECT_FALSE(ParseNaturalNumber("+123", &result)); errno = 0; } TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) { BiggestParsable result = 0; EXPECT_FALSE(ParseNaturalNumber("99999999999999999999999", &result)); signed char char_result = 0; EXPECT_FALSE(ParseNaturalNumber("200", &char_result)); errno = 0; } TEST(ParseNaturalNumberTest, AcceptsValidNumbers) { BiggestParsable result = 0; result = 0; ASSERT_TRUE(ParseNaturalNumber("123", &result)); EXPECT_EQ(123U, result); // Check 0 as an edge case. result = 1; ASSERT_TRUE(ParseNaturalNumber("0", &result)); EXPECT_EQ(0U, result); result = 1; ASSERT_TRUE(ParseNaturalNumber("00000", &result)); EXPECT_EQ(0U, result); } TEST(ParseNaturalNumberTest, AcceptsTypeLimits) { Message msg; msg << kBiggestParsableMax; BiggestParsable result = 0; EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result)); EXPECT_EQ(kBiggestParsableMax, result); Message msg2; msg2 << kBiggestSignedParsableMax; BiggestSignedParsable signed_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result)); EXPECT_EQ(kBiggestSignedParsableMax, signed_result); Message msg3; msg3 << INT_MAX; int int_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result)); EXPECT_EQ(INT_MAX, int_result); Message msg4; msg4 << UINT_MAX; unsigned int uint_result = 0; EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result)); EXPECT_EQ(UINT_MAX, uint_result); } TEST(ParseNaturalNumberTest, WorksForShorterIntegers) { short short_result = 0; ASSERT_TRUE(ParseNaturalNumber("123", &short_result)); EXPECT_EQ(123, short_result); signed char char_result = 0; ASSERT_TRUE(ParseNaturalNumber("123", &char_result)); EXPECT_EQ(123, char_result); } # if GTEST_OS_WINDOWS TEST(EnvironmentTest, HandleFitsIntoSizeT) { // TODO(vladl@google.com): Remove this test after this condition is verified // in a static assertion in gtest-death-test.cc in the function // GetStatusFileDescriptor. ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t)); } # endif // GTEST_OS_WINDOWS // Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger // failures when death tests are available on the system. TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) { EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"), "death inside CondDeathTestExpectMacro"); ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"), "death inside CondDeathTestAssertMacro"); // Empty statement will not crash, which must trigger a failure. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(;, ""), ""); EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), ""); } #else using testing::internal::CaptureStderr; using testing::internal::GetCapturedStderr; // Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still // defined but do not trigger failures when death tests are not available on // the system. TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { // Empty statement will not crash, but that should not trigger a failure // when death tests are not supported. CaptureStderr(); EXPECT_DEATH_IF_SUPPORTED(;, ""); std::string output = GetCapturedStderr(); ASSERT_TRUE(NULL != strstr(output.c_str(), "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); // The streamed message should not be printed as there is no test failure. CaptureStderr(); EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; output = GetCapturedStderr(); ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); CaptureStderr(); ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT output = GetCapturedStderr(); ASSERT_TRUE(NULL != strstr(output.c_str(), "Death tests are not supported on this platform")); ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); CaptureStderr(); ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT output = GetCapturedStderr(); ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); } void FuncWithAssert(int* n) { ASSERT_DEATH_IF_SUPPORTED(return;, ""); (*n)++; } // Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current // function (as ASSERT_DEATH does) if death tests are not supported. TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { int n = 0; FuncWithAssert(&n); EXPECT_EQ(1, n); } TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_FALSE(InDeathTestChild()); EXPECT_DEATH({ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); fflush(stderr); _exit(1); }, "Inside"); } TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_FALSE(InDeathTestChild()); EXPECT_DEATH({ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); fflush(stderr); _exit(1); }, "Inside"); } #endif // GTEST_HAS_DEATH_TEST // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text // comprises only a single C++ statement. // // The syntax should work whether death tests are available or not. TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { if (AlwaysFalse()) // This would fail if executed; this is a compilation test only ASSERT_DEATH_IF_SUPPORTED(return, ""); if (AlwaysTrue()) EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); else // This empty "else" branch is meant to ensure that EXPECT_DEATH // doesn't expand into an "if" statement without an "else" ; // NOLINT if (AlwaysFalse()) ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; if (AlwaysFalse()) ; // NOLINT else EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; } // Tests that conditional death test macros expand to code which interacts // well with switch statements. TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { // Microsoft compiler usually complains about switch statements without // case labels. We suppress that warning for this test. #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4065) #endif // _MSC_VER switch (0) default: ASSERT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in default switch handler"; switch (0) case 0: EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; #ifdef _MSC_VER # pragma warning(pop) #endif // _MSC_VER } // Tests that a test case whose name ends with "DeathTest" works fine // on Windows. TEST(NotADeathTest, Test) { SUCCEED(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-filepath_test.cc000066400000000000000000000561451273231111400303470ustar00rootroot00000000000000// 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) // // Google Test filepath utilities // // This file tests classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included from gtest_unittest.cc, to avoid changing // build or make-files for some existing Google Test clients. Do not // #include this file anywhere else! #include "gtest/internal/gtest-filepath.h" #include "gtest/gtest.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_ #if GTEST_OS_WINDOWS_MOBILE # include // NOLINT #elif GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS_MOBILE namespace testing { namespace internal { namespace { #if GTEST_OS_WINDOWS_MOBILE // TODO(wan@google.com): Move these to the POSIX adapter section in // gtest-port.h. // Windows CE doesn't have the remove C function. int remove(const char* path) { LPCWSTR wpath = String::AnsiToUtf16(path); int ret = DeleteFile(wpath) ? 0 : -1; delete [] wpath; return ret; } // Windows CE doesn't have the _rmdir C function. int _rmdir(const char* path) { FilePath filepath(path); LPCWSTR wpath = String::AnsiToUtf16( filepath.RemoveTrailingPathSeparator().c_str()); int ret = RemoveDirectory(wpath) ? 0 : -1; delete [] wpath; return ret; } #else TEST(GetCurrentDirTest, ReturnsCurrentDir) { const FilePath original_dir = FilePath::GetCurrentDir(); EXPECT_FALSE(original_dir.IsEmpty()); posix::ChDir(GTEST_PATH_SEP_); const FilePath cwd = FilePath::GetCurrentDir(); posix::ChDir(original_dir.c_str()); # if GTEST_OS_WINDOWS // Skips the ":". const char* const cwd_without_drive = strchr(cwd.c_str(), ':'); ASSERT_TRUE(cwd_without_drive != NULL); EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1); # else EXPECT_EQ(GTEST_PATH_SEP_, cwd.string()); # endif } #endif // GTEST_OS_WINDOWS_MOBILE TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { EXPECT_TRUE(FilePath("").IsEmpty()); } TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) { EXPECT_FALSE(FilePath("a").IsEmpty()); EXPECT_FALSE(FilePath(".").IsEmpty()); EXPECT_FALSE(FilePath("a/b").IsEmpty()); EXPECT_FALSE(FilePath("a\\b\\").IsEmpty()); } // RemoveDirectoryName "" -> "" TEST(RemoveDirectoryNameTest, WhenEmptyName) { EXPECT_EQ("", FilePath("").RemoveDirectoryName().string()); } // RemoveDirectoryName "afile" -> "afile" TEST(RemoveDirectoryNameTest, ButNoDirectory) { EXPECT_EQ("afile", FilePath("afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "/afile" -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) { EXPECT_EQ("afile", FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/" -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) { EXPECT_EQ("", FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileName) { EXPECT_EQ("afile", FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/subdir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { EXPECT_EQ("afile", FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveDirectoryName().string()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveDirectoryName() works with the alternate separator // on Windows. // RemoveDirectoryName("/afile") -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("/afile").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/") -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) { EXPECT_EQ("", FilePath("adir/").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("adir/afile").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/subdir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("adir/subdir/afile").RemoveDirectoryName().string()); } #endif // RemoveFileName "" -> "./" TEST(RemoveFileNameTest, EmptyName) { #if GTEST_OS_WINDOWS_MOBILE // On Windows CE, we use the root as the current directory. EXPECT_EQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); #else EXPECT_EQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); #endif } // RemoveFileName "adir/" -> "adir/" TEST(RemoveFileNameTest, ButNoFile) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().string()); } // RemoveFileName "adir/afile" -> "adir/" TEST(RemoveFileNameTest, GivesDirName) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveFileName().string()); } // RemoveFileName "adir/subdir/afile" -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirName) { EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveFileName().string()); } // RemoveFileName "/afile" -> "/" TEST(RemoveFileNameTest, GivesRootDir) { EXPECT_EQ(GTEST_PATH_SEP_, FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().string()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveFileName() works with the alternate separator on // Windows. // RemoveFileName("adir/") -> "adir/" TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir/").RemoveFileName().string()); } // RemoveFileName("adir/afile") -> "adir/" TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir/afile").RemoveFileName().string()); } // RemoveFileName("adir/subdir/afile") -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir/subdir/afile").RemoveFileName().string()); } // RemoveFileName("/afile") -> "\" TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) { EXPECT_EQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().string()); } #endif TEST(MakeFileNameTest, GenerateWhenNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 0, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 12, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 0, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 12, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); } TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 0, "xml"); EXPECT_EQ("bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 14, "xml"); EXPECT_EQ("bar_14.xml", actual.string()); } TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, Path1BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("bar.xml")); EXPECT_EQ("bar.xml", actual.string()); } TEST(ConcatPathsTest, Path2BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("")); EXPECT_EQ("foo" GTEST_PATH_SEP_, actual.string()); } TEST(ConcatPathsTest, BothPathBeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("")); EXPECT_EQ("", actual.string()); } TEST(ConcatPathsTest, Path1ContainsPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"), FilePath("foobar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml", actual.string()); } TEST(ConcatPathsTest, Path2ContainsPathSep) { FilePath actual = FilePath::ConcatPaths( FilePath("foo" GTEST_PATH_SEP_), FilePath("bar" GTEST_PATH_SEP_ "bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, Path2EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar" GTEST_PATH_SEP_)); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.string()); } // RemoveTrailingPathSeparator "" -> "" TEST(RemoveTrailingPathSeparatorTest, EmptyString) { EXPECT_EQ("", FilePath("").RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo" -> "foo" TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) { EXPECT_EQ("foo", FilePath("foo").RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo/" -> "foo" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) { EXPECT_EQ("foo", FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().string()); #if GTEST_HAS_ALT_PATH_SEP_ EXPECT_EQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().string()); #endif } // RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_) .RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo/bar" -> "foo/bar" TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar") .RemoveTrailingPathSeparator().string()); } TEST(DirectoryTest, RootDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. char current_drive[_MAX_PATH]; // NOLINT current_drive[0] = static_cast(_getdrive() + 'A' - 1); current_drive[1] = ':'; current_drive[2] = '\\'; current_drive[3] = '\0'; EXPECT_TRUE(FilePath(current_drive).DirectoryExists()); #else EXPECT_TRUE(FilePath("/").DirectoryExists()); #endif // GTEST_OS_WINDOWS } #if GTEST_OS_WINDOWS TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) { const int saved_drive_ = _getdrive(); // Find a drive that doesn't exist. Start with 'Z' to avoid common ones. for (char drive = 'Z'; drive >= 'A'; drive--) if (_chdrive(drive - 'A' + 1) == -1) { char non_drive[_MAX_PATH]; // NOLINT non_drive[0] = drive; non_drive[1] = ':'; non_drive[2] = '\\'; non_drive[3] = '\0'; EXPECT_FALSE(FilePath(non_drive).DirectoryExists()); break; } _chdrive(saved_drive_); } #endif // GTEST_OS_WINDOWS #if !GTEST_OS_WINDOWS_MOBILE // Windows CE _does_ consider an empty directory to exist. TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) { EXPECT_FALSE(FilePath("").DirectoryExists()); } #endif // !GTEST_OS_WINDOWS_MOBILE TEST(DirectoryTest, CurrentDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. # ifndef _WIN32_CE // Windows CE doesn't have a current directory. EXPECT_TRUE(FilePath(".").DirectoryExists()); EXPECT_TRUE(FilePath(".\\").DirectoryExists()); # endif // _WIN32_CE #else EXPECT_TRUE(FilePath(".").DirectoryExists()); EXPECT_TRUE(FilePath("./").DirectoryExists()); #endif // GTEST_OS_WINDOWS } // "foo/bar" == foo//bar" == "foo///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); } // "/bar" == //bar" == "///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) { EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); } // "foo/" == foo//" == "foo///" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) { EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_).string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that separators at the end of the string are normalized // regardless of their combination (e.g. "foo\" =="foo/\" == // "foo\\/"). TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) { EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo/").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ "/").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo//" GTEST_PATH_SEP_).string()); } #endif TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) { FilePath default_path; FilePath non_default_path("path"); non_default_path = default_path; EXPECT_EQ("", non_default_path.string()); EXPECT_EQ("", default_path.string()); // RHS var is unchanged. } TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) { FilePath non_default_path("path"); FilePath default_path; default_path = non_default_path; EXPECT_EQ("path", default_path.string()); EXPECT_EQ("path", non_default_path.string()); // RHS var is unchanged. } TEST(AssignmentOperatorTest, ConstAssignedToNonConst) { const FilePath const_default_path("const_path"); FilePath non_default_path("path"); non_default_path = const_default_path; EXPECT_EQ("const_path", non_default_path.string()); } class DirectoryCreationTest : public Test { protected: virtual void SetUp() { testdata_path_.Set(FilePath( TempDir() + GetCurrentExecutableName().string() + "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_)); testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator()); unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), 0, "txt")); unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), 1, "txt")); remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); posix::RmDir(testdata_path_.c_str()); } virtual void TearDown() { remove(testdata_file_.c_str()); remove(unique_file0_.c_str()); remove(unique_file1_.c_str()); posix::RmDir(testdata_path_.c_str()); } std::string TempDir() const { #if GTEST_OS_WINDOWS_MOBILE return "\\temp\\"; #elif GTEST_OS_WINDOWS const char* temp_dir = posix::GetEnv("TEMP"); if (temp_dir == NULL || temp_dir[0] == '\0') return "\\temp\\"; else if (temp_dir[strlen(temp_dir) - 1] == '\\') return temp_dir; else return std::string(temp_dir) + "\\"; #elif GTEST_OS_LINUX_ANDROID return "/sdcard/"; #else return "/tmp/"; #endif // GTEST_OS_WINDOWS_MOBILE } void CreateTextFile(const char* filename) { FILE* f = posix::FOpen(filename, "w"); fprintf(f, "text\n"); fclose(f); } // Strings representing a directory and a file, with identical paths // except for the trailing separator character that distinquishes // a directory named 'test' from a file named 'test'. Example names: FilePath testdata_path_; // "/tmp/directory_creation/test/" FilePath testdata_file_; // "/tmp/directory_creation/test" FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt" FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt" }; TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) { EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string(); EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); EXPECT_TRUE(testdata_path_.DirectoryExists()); } TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) { EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string(); EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); // Call 'create' again... should still succeed. EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); } TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) { FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_, FilePath("unique"), "txt")); EXPECT_EQ(unique_file0_.string(), file_path.string()); EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there testdata_path_.CreateDirectoriesRecursively(); EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there CreateTextFile(file_path.c_str()); EXPECT_TRUE(file_path.FileOrDirectoryExists()); FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_, FilePath("unique"), "txt")); EXPECT_EQ(unique_file1_.string(), file_path2.string()); EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there CreateTextFile(file_path2.c_str()); EXPECT_TRUE(file_path2.FileOrDirectoryExists()); } TEST_F(DirectoryCreationTest, CreateDirectoriesFail) { // force a failure by putting a file where we will try to create a directory. CreateTextFile(testdata_file_.c_str()); EXPECT_TRUE(testdata_file_.FileOrDirectoryExists()); EXPECT_FALSE(testdata_file_.DirectoryExists()); EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively()); } TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) { const FilePath test_detail_xml("test_detail.xml"); EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively()); } TEST(FilePathTest, DefaultConstructor) { FilePath fp; EXPECT_EQ("", fp.string()); } TEST(FilePathTest, CharAndCopyConstructors) { const FilePath fp("spicy"); EXPECT_EQ("spicy", fp.string()); const FilePath fp_copy(fp); EXPECT_EQ("spicy", fp_copy.string()); } TEST(FilePathTest, StringConstructor) { const FilePath fp(std::string("cider")); EXPECT_EQ("cider", fp.string()); } TEST(FilePathTest, Set) { const FilePath apple("apple"); FilePath mac("mac"); mac.Set(apple); // Implement Set() since overloading operator= is forbidden. EXPECT_EQ("apple", mac.string()); EXPECT_EQ("apple", apple.string()); } TEST(FilePathTest, ToString) { const FilePath file("drink"); EXPECT_EQ("drink", file.string()); } TEST(FilePathTest, RemoveExtension) { EXPECT_EQ("app", FilePath("app.cc").RemoveExtension("cc").string()); EXPECT_EQ("app", FilePath("app.exe").RemoveExtension("exe").string()); EXPECT_EQ("APP", FilePath("APP.EXE").RemoveExtension("exe").string()); } TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) { EXPECT_EQ("app", FilePath("app").RemoveExtension("exe").string()); } TEST(FilePathTest, IsDirectory) { EXPECT_FALSE(FilePath("cola").IsDirectory()); EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory()); #if GTEST_HAS_ALT_PATH_SEP_ EXPECT_TRUE(FilePath("koala/").IsDirectory()); #endif } TEST(FilePathTest, IsAbsolutePath) { EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); EXPECT_FALSE(FilePath("").IsAbsolutePath()); #if GTEST_OS_WINDOWS EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath()); EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); #else EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative") .IsAbsolutePath()); #endif // GTEST_OS_WINDOWS } TEST(FilePathTest, IsRootDirectory) { #if GTEST_OS_WINDOWS EXPECT_TRUE(FilePath("a:\\").IsRootDirectory()); EXPECT_TRUE(FilePath("Z:/").IsRootDirectory()); EXPECT_TRUE(FilePath("e://").IsRootDirectory()); EXPECT_FALSE(FilePath("").IsRootDirectory()); EXPECT_FALSE(FilePath("b:").IsRootDirectory()); EXPECT_FALSE(FilePath("b:a").IsRootDirectory()); EXPECT_FALSE(FilePath("8:/").IsRootDirectory()); EXPECT_FALSE(FilePath("c|/").IsRootDirectory()); #else EXPECT_TRUE(FilePath("/").IsRootDirectory()); EXPECT_TRUE(FilePath("//").IsRootDirectory()); EXPECT_FALSE(FilePath("").IsRootDirectory()); EXPECT_FALSE(FilePath("\\").IsRootDirectory()); EXPECT_FALSE(FilePath("/x").IsRootDirectory()); #endif } } // namespace } // namespace internal } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-linked_ptr_test.cc000066400000000000000000000100351273231111400306720ustar00rootroot00000000000000// 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) // Ported to Windows: Vadim Berman (vadimb@google.com) #include "gtest/internal/gtest-linked_ptr.h" #include #include "gtest/gtest.h" namespace { using testing::Message; using testing::internal::linked_ptr; int num; Message* history = NULL; // Class which tracks allocation/deallocation class A { public: A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; } virtual ~A() { *history << "A" << mynum << " dtor\n"; } virtual void Use() { *history << "A" << mynum << " use\n"; } protected: int mynum; }; // Subclass class B : public A { public: B() { *history << "B" << mynum << " ctor\n"; } ~B() { *history << "B" << mynum << " dtor\n"; } virtual void Use() { *history << "B" << mynum << " use\n"; } }; class LinkedPtrTest : public testing::Test { public: LinkedPtrTest() { num = 0; history = new Message; } virtual ~LinkedPtrTest() { delete history; history = NULL; } }; TEST_F(LinkedPtrTest, GeneralTest) { { linked_ptr a0, a1, a2; // Use explicit function call notation here to suppress self-assign warning. a0.operator=(a0); a1 = a2; ASSERT_EQ(a0.get(), static_cast(NULL)); ASSERT_EQ(a1.get(), static_cast(NULL)); ASSERT_EQ(a2.get(), static_cast(NULL)); ASSERT_TRUE(a0 == NULL); ASSERT_TRUE(a1 == NULL); ASSERT_TRUE(a2 == NULL); { linked_ptr a3(new A); a0 = a3; ASSERT_TRUE(a0 == a3); ASSERT_TRUE(a0 != NULL); ASSERT_TRUE(a0.get() == a3); ASSERT_TRUE(a0 == a3.get()); linked_ptr a4(a0); a1 = a4; linked_ptr a5(new A); ASSERT_TRUE(a5.get() != a3); ASSERT_TRUE(a5 != a3.get()); a2 = a5; linked_ptr b0(new B); linked_ptr a6(b0); ASSERT_TRUE(b0 == a6); ASSERT_TRUE(a6 == b0); ASSERT_TRUE(b0 != NULL); a5 = b0; a5 = b0; a3->Use(); a4->Use(); a5->Use(); a6->Use(); b0->Use(); (*b0).Use(); b0.get()->Use(); } a0->Use(); a1->Use(); a2->Use(); a1 = a2; a2.reset(new A); a0.reset(); linked_ptr a7; } ASSERT_STREQ( "A0 ctor\n" "A1 ctor\n" "A2 ctor\n" "B2 ctor\n" "A0 use\n" "A0 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 use\n" "B2 dtor\n" "A2 dtor\n" "A0 use\n" "A0 use\n" "A1 use\n" "A3 ctor\n" "A0 dtor\n" "A3 dtor\n" "A1 dtor\n", history->GetString().c_str()); } } // Unnamed namespace mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-listener_test.cc000066400000000000000000000230671273231111400303750ustar00rootroot00000000000000// Copyright 2009 Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This file verifies Google Test event listeners receive events at the // right times. #include "gtest/gtest.h" #include using ::testing::AddGlobalTestEnvironment; using ::testing::Environment; using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::TestCase; using ::testing::TestEventListener; using ::testing::TestInfo; using ::testing::TestPartResult; using ::testing::UnitTest; // Used by tests to register their events. std::vector* g_events = NULL; namespace testing { namespace internal { class EventRecordingListener : public TestEventListener { public: explicit EventRecordingListener(const char* name) : name_(name) {} protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnTestProgramStart")); } virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int iteration) { Message message; message << GetFullMethodName("OnTestIterationStart") << "(" << iteration << ")"; g_events->push_back(message.GetString()); } virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart")); } virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd")); } virtual void OnTestCaseStart(const TestCase& /*test_case*/) { g_events->push_back(GetFullMethodName("OnTestCaseStart")); } virtual void OnTestStart(const TestInfo& /*test_info*/) { g_events->push_back(GetFullMethodName("OnTestStart")); } virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) { g_events->push_back(GetFullMethodName("OnTestPartResult")); } virtual void OnTestEnd(const TestInfo& /*test_info*/) { g_events->push_back(GetFullMethodName("OnTestEnd")); } virtual void OnTestCaseEnd(const TestCase& /*test_case*/) { g_events->push_back(GetFullMethodName("OnTestCaseEnd")); } virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart")); } virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd")); } virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int iteration) { Message message; message << GetFullMethodName("OnTestIterationEnd") << "(" << iteration << ")"; g_events->push_back(message.GetString()); } virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { g_events->push_back(GetFullMethodName("OnTestProgramEnd")); } private: std::string GetFullMethodName(const char* name) { return name_ + "." + name; } std::string name_; }; class EnvironmentInvocationCatcher : public Environment { protected: virtual void SetUp() { g_events->push_back("Environment::SetUp"); } virtual void TearDown() { g_events->push_back("Environment::TearDown"); } }; class ListenerTest : public Test { protected: static void SetUpTestCase() { g_events->push_back("ListenerTest::SetUpTestCase"); } static void TearDownTestCase() { g_events->push_back("ListenerTest::TearDownTestCase"); } virtual void SetUp() { g_events->push_back("ListenerTest::SetUp"); } virtual void TearDown() { g_events->push_back("ListenerTest::TearDown"); } }; TEST_F(ListenerTest, DoesFoo) { // Test execution order within a test case is not guaranteed so we are not // recording the test name. g_events->push_back("ListenerTest::* Test Body"); SUCCEED(); // Triggers OnTestPartResult. } TEST_F(ListenerTest, DoesBar) { g_events->push_back("ListenerTest::* Test Body"); SUCCEED(); // Triggers OnTestPartResult. } } // namespace internal } // namespace testing using ::testing::internal::EnvironmentInvocationCatcher; using ::testing::internal::EventRecordingListener; void VerifyResults(const std::vector& data, const char* const* expected_data, int expected_data_size) { const int actual_size = data.size(); // If the following assertion fails, a new entry will be appended to // data. Hence we save data.size() first. EXPECT_EQ(expected_data_size, actual_size); // Compares the common prefix. const int shorter_size = expected_data_size <= actual_size ? expected_data_size : actual_size; int i = 0; for (; i < shorter_size; ++i) { ASSERT_STREQ(expected_data[i], data[i].c_str()) << "at position " << i; } // Prints extra elements in the actual data. for (; i < actual_size; ++i) { printf(" Actual event #%d: %s\n", i, data[i].c_str()); } } int main(int argc, char **argv) { std::vector events; g_events = &events; InitGoogleTest(&argc, argv); UnitTest::GetInstance()->listeners().Append( new EventRecordingListener("1st")); UnitTest::GetInstance()->listeners().Append( new EventRecordingListener("2nd")); AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); GTEST_CHECK_(events.size() == 0) << "AddGlobalTestEnvironment should not generate any events itself."; ::testing::GTEST_FLAG(repeat) = 2; int ret_val = RUN_ALL_TESTS(); const char* const expected_events[] = { "1st.OnTestProgramStart", "2nd.OnTestProgramStart", "1st.OnTestIterationStart(0)", "2nd.OnTestIterationStart(0)", "1st.OnEnvironmentsSetUpStart", "2nd.OnEnvironmentsSetUpStart", "Environment::SetUp", "2nd.OnEnvironmentsSetUpEnd", "1st.OnEnvironmentsSetUpEnd", "1st.OnTestCaseStart", "2nd.OnTestCaseStart", "ListenerTest::SetUpTestCase", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "ListenerTest::TearDownTestCase", "2nd.OnTestCaseEnd", "1st.OnTestCaseEnd", "1st.OnEnvironmentsTearDownStart", "2nd.OnEnvironmentsTearDownStart", "Environment::TearDown", "2nd.OnEnvironmentsTearDownEnd", "1st.OnEnvironmentsTearDownEnd", "2nd.OnTestIterationEnd(0)", "1st.OnTestIterationEnd(0)", "1st.OnTestIterationStart(1)", "2nd.OnTestIterationStart(1)", "1st.OnEnvironmentsSetUpStart", "2nd.OnEnvironmentsSetUpStart", "Environment::SetUp", "2nd.OnEnvironmentsSetUpEnd", "1st.OnEnvironmentsSetUpEnd", "1st.OnTestCaseStart", "2nd.OnTestCaseStart", "ListenerTest::SetUpTestCase", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "1st.OnTestStart", "2nd.OnTestStart", "ListenerTest::SetUp", "ListenerTest::* Test Body", "1st.OnTestPartResult", "2nd.OnTestPartResult", "ListenerTest::TearDown", "2nd.OnTestEnd", "1st.OnTestEnd", "ListenerTest::TearDownTestCase", "2nd.OnTestCaseEnd", "1st.OnTestCaseEnd", "1st.OnEnvironmentsTearDownStart", "2nd.OnEnvironmentsTearDownStart", "Environment::TearDown", "2nd.OnEnvironmentsTearDownEnd", "1st.OnEnvironmentsTearDownEnd", "2nd.OnTestIterationEnd(1)", "1st.OnTestIterationEnd(1)", "2nd.OnTestProgramEnd", "1st.OnTestProgramEnd" }; VerifyResults(events, expected_events, sizeof(expected_events)/sizeof(expected_events[0])); // We need to check manually for ad hoc test failures that happen after // RUN_ALL_TESTS finishes. if (UnitTest::GetInstance()->Failed()) ret_val = 1; return ret_val; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-message_test.cc000066400000000000000000000122661273231111400301730ustar00rootroot00000000000000// 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) // // Tests for the Message class. #include "gtest/gtest-message.h" #include "gtest/gtest.h" namespace { using ::testing::Message; // Tests the testing::Message class // Tests the default constructor. TEST(MessageTest, DefaultConstructor) { const Message msg; EXPECT_EQ("", msg.GetString()); } // Tests the copy constructor. TEST(MessageTest, CopyConstructor) { const Message msg1("Hello"); const Message msg2(msg1); EXPECT_EQ("Hello", msg2.GetString()); } // Tests constructing a Message from a C-string. TEST(MessageTest, ConstructsFromCString) { Message msg("Hello"); EXPECT_EQ("Hello", msg.GetString()); } // Tests streaming a float. TEST(MessageTest, StreamsFloat) { const std::string s = (Message() << 1.23456F << " " << 2.34567F).GetString(); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s.c_str()); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s.c_str()); } // Tests streaming a double. TEST(MessageTest, StreamsDouble) { const std::string s = (Message() << 1260570880.4555497 << " " << 1260572265.1954534).GetString(); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s.c_str()); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s.c_str()); } // Tests streaming a non-char pointer. TEST(MessageTest, StreamsPointer) { int n = 0; int* p = &n; EXPECT_NE("(null)", (Message() << p).GetString()); } // Tests streaming a NULL non-char pointer. TEST(MessageTest, StreamsNullPointer) { int* p = NULL; EXPECT_EQ("(null)", (Message() << p).GetString()); } // Tests streaming a C string. TEST(MessageTest, StreamsCString) { EXPECT_EQ("Foo", (Message() << "Foo").GetString()); } // Tests streaming a NULL C string. TEST(MessageTest, StreamsNullCString) { char* p = NULL; EXPECT_EQ("(null)", (Message() << p).GetString()); } // Tests streaming std::string. TEST(MessageTest, StreamsString) { const ::std::string str("Hello"); EXPECT_EQ("Hello", (Message() << str).GetString()); } // Tests that we can output strings containing embedded NULs. TEST(MessageTest, StreamsStringWithEmbeddedNUL) { const char char_array_with_nul[] = "Here's a NUL\0 and some more string"; const ::std::string string_with_nul(char_array_with_nul, sizeof(char_array_with_nul) - 1); EXPECT_EQ("Here's a NUL\\0 and some more string", (Message() << string_with_nul).GetString()); } // Tests streaming a NUL char. TEST(MessageTest, StreamsNULChar) { EXPECT_EQ("\\0", (Message() << '\0').GetString()); } // Tests streaming int. TEST(MessageTest, StreamsInt) { EXPECT_EQ("123", (Message() << 123).GetString()); } // Tests that basic IO manipulators (endl, ends, and flush) can be // streamed to Message. TEST(MessageTest, StreamsBasicIoManip) { EXPECT_EQ("Line 1.\nA NUL char \\0 in line 2.", (Message() << "Line 1." << std::endl << "A NUL char " << std::ends << std::flush << " in line 2.").GetString()); } // Tests Message::GetString() TEST(MessageTest, GetString) { Message msg; msg << 1 << " lamb"; EXPECT_EQ("1 lamb", msg.GetString()); } // Tests streaming a Message object to an ostream. TEST(MessageTest, StreamsToOStream) { Message msg("Hello"); ::std::stringstream ss; ss << msg; EXPECT_EQ("Hello", testing::internal::StringStreamToString(&ss)); } // Tests that a Message object doesn't take up too much stack space. TEST(MessageTest, DoesNotTakeUpMuchStackSpace) { EXPECT_LE(sizeof(Message), 16U); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-options_test.cc000066400000000000000000000174021273231111400302370ustar00rootroot00000000000000// 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) // // Google Test UnitTestOptions tests // // This file tests classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included from gtest.cc, to avoid changing build or // make-files on Windows and other platforms. Do not #include this file // anywhere else! #include "gtest/gtest.h" #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include #endif // GTEST_OS_WINDOWS_MOBILE // 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 { namespace { // Turns the given relative path into an absolute path. FilePath GetAbsolutePathOf(const FilePath& relative_path) { return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path); } // Testing UnitTestOptions::GetOutputFormat/GetOutputFile. TEST(XmlOutputTest, GetOutputFormatDefault) { GTEST_FLAG(output) = ""; EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str()); } TEST(XmlOutputTest, GetOutputFormat) { GTEST_FLAG(output) = "xml:filename"; EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str()); } TEST(XmlOutputTest, GetOutputFileDefault) { GTEST_FLAG(output) = ""; EXPECT_EQ(GetAbsolutePathOf(FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST(XmlOutputTest, GetOutputFileSingleFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_EQ(GetAbsolutePathOf(FilePath("filename.abc")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; const std::string expected_output_file = GetAbsolutePathOf( FilePath(std::string("path") + GTEST_PATH_SEP_ + GetCurrentExecutableName().string() + ".xml")).string(); const std::string& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } TEST(OutputFileHelpersTest, GetCurrentExecutableName) { const std::string exe_str = GetCurrentExecutableName().string(); #if GTEST_OS_WINDOWS const bool success = _strcmpi("gtest-options_test", exe_str.c_str()) == 0 || _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 || _strcmpi("gtest_all_test", exe_str.c_str()) == 0 || _strcmpi("gtest_dll_test", exe_str.c_str()) == 0; #else // TODO(wan@google.com): remove the hard-coded "lt-" prefix when // Chandler Carruth's libtool replacement is ready. const bool success = exe_str == "gtest-options_test" || exe_str == "gtest_all_test" || exe_str == "lt-gtest_all_test" || exe_str == "gtest_dll_test"; #endif // GTEST_OS_WINDOWS if (!success) FAIL() << "GetCurrentExecutableName() returns " << exe_str; } class XmlOutputChangeDirTest : public Test { protected: virtual void SetUp() { original_working_dir_ = FilePath::GetCurrentDir(); posix::ChDir(".."); // This will make the test fail if run from the root directory. EXPECT_NE(original_working_dir_.string(), FilePath::GetCurrentDir().string()); } virtual void TearDown() { posix::ChDir(original_working_dir_.string().c_str()); } FilePath original_working_dir_; }; TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) { GTEST_FLAG(output) = ""; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) { GTEST_FLAG(output) = "xml"; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("filename.abc")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; const std::string expected_output_file = FilePath::ConcatPaths( original_working_dir_, FilePath(std::string("path") + GTEST_PATH_SEP_ + GetCurrentExecutableName().string() + ".xml")).string(); const std::string& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile) { #if GTEST_OS_WINDOWS GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc"; EXPECT_EQ(FilePath("c:\\tmp\\filename.abc").string(), UnitTestOptions::GetAbsolutePathToOutputFile()); #else GTEST_FLAG(output) ="xml:/tmp/filename.abc"; EXPECT_EQ(FilePath("/tmp/filename.abc").string(), UnitTestOptions::GetAbsolutePathToOutputFile()); #endif } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { #if GTEST_OS_WINDOWS const std::string path = "c:\\tmp\\"; #else const std::string path = "/tmp/"; #endif GTEST_FLAG(output) = "xml:" + path; const std::string expected_output_file = path + GetCurrentExecutableName().string() + ".xml"; const std::string& output_file = UnitTestOptions::GetAbsolutePathToOutputFile(); #if GTEST_OS_WINDOWS EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); #else EXPECT_EQ(expected_output_file, output_file.c_str()); #endif } } // namespace } // namespace internal } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-param-test2_test.cc000066400000000000000000000055041273231111400307030ustar00rootroot00000000000000// 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) // // Tests for Google Test itself. This verifies that the basic constructs of // Google Test work. #include "gtest/gtest.h" #include "test/gtest-param-test_test.h" #if GTEST_HAS_PARAM_TEST using ::testing::Values; using ::testing::internal::ParamGenerator; // Tests that generators defined in a different translation unit // are functional. The test using extern_gen is defined // in gtest-param-test_test.cc. ParamGenerator extern_gen = Values(33); // Tests that a parameterized test case can be defined in one translation unit // and instantiated in another. The test is defined in gtest-param-test_test.cc // and ExternalInstantiationTest fixture class is defined in // gtest-param-test_test.h. INSTANTIATE_TEST_CASE_P(MultiplesOf33, ExternalInstantiationTest, Values(33, 66)); // Tests that a parameterized test case can be instantiated // in multiple translation units. Another instantiation is defined // in gtest-param-test_test.cc and InstantiationInMultipleTranslaionUnitsTest // fixture is defined in gtest-param-test_test.h INSTANTIATE_TEST_CASE_P(Sequence2, InstantiationInMultipleTranslaionUnitsTest, Values(42*3, 42*4, 42*5)); #endif // GTEST_HAS_PARAM_TEST mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-param-test_test.cc000066400000000000000000001011021273231111400306100ustar00rootroot00000000000000// 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) // // Tests for Google Test itself. This file verifies that the parameter // generators objects produce correct parameter sequences and that // Google Test runtime instantiates correct tests from those sequences. #include "gtest/gtest.h" #if GTEST_HAS_PARAM_TEST # include # include # include # include # include # include // To include gtest-internal-inl.h. # define GTEST_IMPLEMENTATION_ 1 # include "src/gtest-internal-inl.h" // for UnitTestOptions # undef GTEST_IMPLEMENTATION_ # include "test/gtest-param-test_test.h" using ::std::vector; using ::std::sort; using ::testing::AddGlobalTestEnvironment; using ::testing::Bool; using ::testing::Message; using ::testing::Range; using ::testing::TestWithParam; using ::testing::Values; using ::testing::ValuesIn; # if GTEST_HAS_COMBINE using ::testing::Combine; using ::std::tr1::get; using ::std::tr1::make_tuple; using ::std::tr1::tuple; # endif // GTEST_HAS_COMBINE using ::testing::internal::ParamGenerator; using ::testing::internal::UnitTestOptions; // Prints a value to a string. // // TODO(wan@google.com): remove PrintValue() when we move matchers and // EXPECT_THAT() from Google Mock to Google Test. At that time, we // can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as // EXPECT_THAT() and the matchers know how to print tuples. template ::std::string PrintValue(const T& value) { ::std::stringstream stream; stream << value; return stream.str(); } # if GTEST_HAS_COMBINE // These overloads allow printing tuples in our tests. We cannot // define an operator<< for tuples, as that definition needs to be in // the std namespace in order to be picked up by Google Test via // Argument-Dependent Lookup, yet defining anything in the std // namespace in non-STL code is undefined behavior. template ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ")"; return stream.str(); } template ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ", "<< get<2>(value) << ")"; return stream.str(); } template ::std::string PrintValue( const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ", "<< get<2>(value) << ", " << get<3>(value) << ", "<< get<4>(value) << ", " << get<5>(value) << ", "<< get<6>(value) << ", " << get<7>(value) << ", "<< get<8>(value) << ", " << get<9>(value) << ")"; return stream.str(); } # endif // GTEST_HAS_COMBINE // Verifies that a sequence generated by the generator and accessed // via the iterator object matches the expected one using Google Test // assertions. template void VerifyGenerator(const ParamGenerator& generator, const T (&expected_values)[N]) { typename ParamGenerator::iterator it = generator.begin(); for (size_t i = 0; i < N; ++i) { ASSERT_FALSE(it == generator.end()) << "At element " << i << " when accessing via an iterator " << "created with the copy constructor.\n"; // We cannot use EXPECT_EQ() here as the values may be tuples, // which don't support <<. EXPECT_TRUE(expected_values[i] == *it) << "where i is " << i << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; it++; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " << "created with the copy constructor.\n"; // Test the iterator assignment. The following lines verify that // the sequence accessed via an iterator initialized via the // assignment operator (as opposed to a copy constructor) matches // just the same. it = generator.begin(); for (size_t i = 0; i < N; ++i) { ASSERT_FALSE(it == generator.end()) << "At element " << i << " when accessing via an iterator " << "created with the assignment operator.\n"; EXPECT_TRUE(expected_values[i] == *it) << "where i is " << i << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; it++; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " << "created with the assignment operator.\n"; } template void VerifyGeneratorIsEmpty(const ParamGenerator& generator) { typename ParamGenerator::iterator it = generator.begin(); EXPECT_TRUE(it == generator.end()); it = generator.begin(); EXPECT_TRUE(it == generator.end()); } // Generator tests. They test that each of the provided generator functions // generates an expected sequence of values. The general test pattern // instantiates a generator using one of the generator functions, // checks the sequence produced by the generator using its iterator API, // and then resets the iterator back to the beginning of the sequence // and checks the sequence again. // Tests that iterators produced by generator functions conform to the // ForwardIterator concept. TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { const ParamGenerator gen = Range(0, 10); ParamGenerator::iterator it = gen.begin(); // Verifies that iterator initialization works as expected. ParamGenerator::iterator it2 = it; EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the " << "element same as its source points to"; // Verifies that iterator assignment works as expected. it++; EXPECT_FALSE(*it == *it2); it2 = it; EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " << "element same as its source points to"; // Verifies that prefix operator++() returns *this. EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be " << "refer to the original object"; // Verifies that the result of the postfix operator++ points to the value // pointed to by the original iterator. int original_value = *it; // Have to compute it outside of macro call to be // unaffected by the parameter evaluation order. EXPECT_EQ(original_value, *(it++)); // Verifies that prefix and postfix operator++() advance an iterator // all the same. it2 = it; it++; ++it2; EXPECT_TRUE(*it == *it2); } // Tests that Range() generates the expected sequence. TEST(RangeTest, IntRangeWithDefaultStep) { const ParamGenerator gen = Range(0, 3); const int expected_values[] = {0, 1, 2}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that Range() generates the single element sequence // as expected when provided with range limits that are equal. TEST(RangeTest, IntRangeSingleValue) { const ParamGenerator gen = Range(0, 1); const int expected_values[] = {0}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that Range() with generates empty sequence when // supplied with an empty range. TEST(RangeTest, IntRangeEmpty) { const ParamGenerator gen = Range(0, 0); VerifyGeneratorIsEmpty(gen); } // Tests that Range() with custom step (greater then one) generates // the expected sequence. TEST(RangeTest, IntRangeWithCustomStep) { const ParamGenerator gen = Range(0, 9, 3); const int expected_values[] = {0, 3, 6}; VerifyGenerator(gen, expected_values); } // Tests that Range() with custom step (greater then one) generates // the expected sequence when the last element does not fall on the // upper range limit. Sequences generated by Range() must not have // elements beyond the range limits. TEST(RangeTest, IntRangeWithCustomStepOverUpperBound) { const ParamGenerator gen = Range(0, 4, 3); const int expected_values[] = {0, 3}; VerifyGenerator(gen, expected_values); } // Verifies that Range works with user-defined types that define // copy constructor, operator=(), operator+(), and operator<(). class DogAdder { public: explicit DogAdder(const char* a_value) : value_(a_value) {} DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {} DogAdder operator=(const DogAdder& other) { if (this != &other) value_ = other.value_; return *this; } DogAdder operator+(const DogAdder& other) const { Message msg; msg << value_.c_str() << other.value_.c_str(); return DogAdder(msg.GetString().c_str()); } bool operator<(const DogAdder& other) const { return value_ < other.value_; } const std::string& value() const { return value_; } private: std::string value_; }; TEST(RangeTest, WorksWithACustomType) { const ParamGenerator gen = Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog")); ParamGenerator::iterator it = gen.begin(); ASSERT_FALSE(it == gen.end()); EXPECT_STREQ("cat", it->value().c_str()); ASSERT_FALSE(++it == gen.end()); EXPECT_STREQ("catdog", it->value().c_str()); EXPECT_TRUE(++it == gen.end()); } class IntWrapper { public: explicit IntWrapper(int a_value) : value_(a_value) {} IntWrapper(const IntWrapper& other) : value_(other.value_) {} IntWrapper operator=(const IntWrapper& other) { value_ = other.value_; return *this; } // operator+() adds a different type. IntWrapper operator+(int other) const { return IntWrapper(value_ + other); } bool operator<(const IntWrapper& other) const { return value_ < other.value_; } int value() const { return value_; } private: int value_; }; TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType) { const ParamGenerator gen = Range(IntWrapper(0), IntWrapper(2)); ParamGenerator::iterator it = gen.begin(); ASSERT_FALSE(it == gen.end()); EXPECT_EQ(0, it->value()); ASSERT_FALSE(++it == gen.end()); EXPECT_EQ(1, it->value()); EXPECT_TRUE(++it == gen.end()); } // Tests that ValuesIn() with an array parameter generates // the expected sequence. TEST(ValuesInTest, ValuesInArray) { int array[] = {3, 5, 8}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Tests that ValuesIn() with a const array parameter generates // the expected sequence. TEST(ValuesInTest, ValuesInConstArray) { const int array[] = {3, 5, 8}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Edge case. Tests that ValuesIn() with an array parameter containing a // single element generates the single element sequence. TEST(ValuesInTest, ValuesInSingleElementArray) { int array[] = {42}; const ParamGenerator gen = ValuesIn(array); VerifyGenerator(gen, array); } // Tests that ValuesIn() generates the expected sequence for an STL // container (vector). TEST(ValuesInTest, ValuesInVector) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator gen = ValuesIn(values); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Tests that ValuesIn() generates the expected sequence. TEST(ValuesInTest, ValuesInIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator gen = ValuesIn(values.begin(), values.end()); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that ValuesIn() provided with an iterator range specifying a // single value generates a single-element sequence. TEST(ValuesInTest, ValuesInSingleElementIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(42); const ParamGenerator gen = ValuesIn(values.begin(), values.end()); const int expected_values[] = {42}; VerifyGenerator(gen, expected_values); } // Edge case. Tests that ValuesIn() provided with an empty iterator range // generates an empty sequence. TEST(ValuesInTest, ValuesInEmptyIteratorRange) { typedef ::std::vector ContainerType; ContainerType values; const ParamGenerator gen = ValuesIn(values.begin(), values.end()); VerifyGeneratorIsEmpty(gen); } // Tests that the Values() generates the expected sequence. TEST(ValuesTest, ValuesWorks) { const ParamGenerator gen = Values(3, 5, 8); const int expected_values[] = {3, 5, 8}; VerifyGenerator(gen, expected_values); } // Tests that Values() generates the expected sequences from elements of // different types convertible to ParamGenerator's parameter type. TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes) { const ParamGenerator gen = Values(3, 5.0f, 8.0); const double expected_values[] = {3.0, 5.0, 8.0}; VerifyGenerator(gen, expected_values); } TEST(ValuesTest, ValuesWorksForMaxLengthList) { const ParamGenerator gen = Values( 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500); const int expected_values[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500}; VerifyGenerator(gen, expected_values); } // Edge case test. Tests that single-parameter Values() generates the sequence // with the single value. TEST(ValuesTest, ValuesWithSingleParameter) { const ParamGenerator gen = Values(42); const int expected_values[] = {42}; VerifyGenerator(gen, expected_values); } // Tests that Bool() generates sequence (false, true). TEST(BoolTest, BoolWorks) { const ParamGenerator gen = Bool(); const bool expected_values[] = {false, true}; VerifyGenerator(gen, expected_values); } # if GTEST_HAS_COMBINE // Tests that Combine() with two parameters generates the expected sequence. TEST(CombineTest, CombineWithTwoParameters) { const char* foo = "foo"; const char* bar = "bar"; const ParamGenerator > gen = Combine(Values(foo, bar), Values(3, 4)); tuple expected_values[] = { make_tuple(foo, 3), make_tuple(foo, 4), make_tuple(bar, 3), make_tuple(bar, 4)}; VerifyGenerator(gen, expected_values); } // Tests that Combine() with three parameters generates the expected sequence. TEST(CombineTest, CombineWithThreeParameters) { const ParamGenerator > gen = Combine(Values(0, 1), Values(3, 4), Values(5, 6)); tuple expected_values[] = { make_tuple(0, 3, 5), make_tuple(0, 3, 6), make_tuple(0, 4, 5), make_tuple(0, 4, 6), make_tuple(1, 3, 5), make_tuple(1, 3, 6), make_tuple(1, 4, 5), make_tuple(1, 4, 6)}; VerifyGenerator(gen, expected_values); } // Tests that the Combine() with the first parameter generating a single value // sequence generates a sequence with the number of elements equal to the // number of elements in the sequence generated by the second parameter. TEST(CombineTest, CombineWithFirstParameterSingleValue) { const ParamGenerator > gen = Combine(Values(42), Values(0, 1)); tuple expected_values[] = {make_tuple(42, 0), make_tuple(42, 1)}; VerifyGenerator(gen, expected_values); } // Tests that the Combine() with the second parameter generating a single value // sequence generates a sequence with the number of elements equal to the // number of elements in the sequence generated by the first parameter. TEST(CombineTest, CombineWithSecondParameterSingleValue) { const ParamGenerator > gen = Combine(Values(0, 1), Values(42)); tuple expected_values[] = {make_tuple(0, 42), make_tuple(1, 42)}; VerifyGenerator(gen, expected_values); } // Tests that when the first parameter produces an empty sequence, // Combine() produces an empty sequence, too. TEST(CombineTest, CombineWithFirstParameterEmptyRange) { const ParamGenerator > gen = Combine(Range(0, 0), Values(0, 1)); VerifyGeneratorIsEmpty(gen); } // Tests that when the second parameter produces an empty sequence, // Combine() produces an empty sequence, too. TEST(CombineTest, CombineWithSecondParameterEmptyRange) { const ParamGenerator > gen = Combine(Values(0, 1), Range(1, 1)); VerifyGeneratorIsEmpty(gen); } // Edge case. Tests that combine works with the maximum number // of parameters supported by Google Test (currently 10). TEST(CombineTest, CombineWithMaxNumberOfParameters) { const char* foo = "foo"; const char* bar = "bar"; const ParamGenerator > gen = Combine(Values(foo, bar), Values(1), Values(2), Values(3), Values(4), Values(5), Values(6), Values(7), Values(8), Values(9)); tuple expected_values[] = {make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9), make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)}; VerifyGenerator(gen, expected_values); } # endif // GTEST_HAS_COMBINE // Tests that an generator produces correct sequence after being // assigned from another generator. TEST(ParamGeneratorTest, AssignmentWorks) { ParamGenerator gen = Values(1, 2); const ParamGenerator gen2 = Values(3, 4); gen = gen2; const int expected_values[] = {3, 4}; VerifyGenerator(gen, expected_values); } // This test verifies that the tests are expanded and run as specified: // one test per element from the sequence produced by the generator // specified in INSTANTIATE_TEST_CASE_P. It also verifies that the test's // fixture constructor, SetUp(), and TearDown() have run and have been // supplied with the correct parameters. // The use of environment object allows detection of the case where no test // case functionality is run at all. In this case TestCaseTearDown will not // be able to detect missing tests, naturally. template class TestGenerationEnvironment : public ::testing::Environment { public: static TestGenerationEnvironment* Instance() { static TestGenerationEnvironment* instance = new TestGenerationEnvironment; return instance; } void FixtureConstructorExecuted() { fixture_constructor_count_++; } void SetUpExecuted() { set_up_count_++; } void TearDownExecuted() { tear_down_count_++; } void TestBodyExecuted() { test_body_count_++; } virtual void TearDown() { // If all MultipleTestGenerationTest tests have been de-selected // by the filter flag, the following checks make no sense. bool perform_check = false; for (int i = 0; i < kExpectedCalls; ++i) { Message msg; msg << "TestsExpandedAndRun/" << i; if (UnitTestOptions::FilterMatchesTest( "TestExpansionModule/MultipleTestGenerationTest", msg.GetString().c_str())) { perform_check = true; } } if (perform_check) { EXPECT_EQ(kExpectedCalls, fixture_constructor_count_) << "Fixture constructor of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, set_up_count_) << "Fixture SetUp method of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, tear_down_count_) << "Fixture TearDown method of ParamTestGenerationTest test case " << "has not been run as expected."; EXPECT_EQ(kExpectedCalls, test_body_count_) << "Test in ParamTestGenerationTest test case " << "has not been run as expected."; } } private: TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0), tear_down_count_(0), test_body_count_(0) {} int fixture_constructor_count_; int set_up_count_; int tear_down_count_; int test_body_count_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment); }; const int test_generation_params[] = {36, 42, 72}; class TestGenerationTest : public TestWithParam { public: enum { PARAMETER_COUNT = sizeof(test_generation_params)/sizeof(test_generation_params[0]) }; typedef TestGenerationEnvironment Environment; TestGenerationTest() { Environment::Instance()->FixtureConstructorExecuted(); current_parameter_ = GetParam(); } virtual void SetUp() { Environment::Instance()->SetUpExecuted(); EXPECT_EQ(current_parameter_, GetParam()); } virtual void TearDown() { Environment::Instance()->TearDownExecuted(); EXPECT_EQ(current_parameter_, GetParam()); } static void SetUpTestCase() { bool all_tests_in_test_case_selected = true; for (int i = 0; i < PARAMETER_COUNT; ++i) { Message test_name; test_name << "TestsExpandedAndRun/" << i; if ( !UnitTestOptions::FilterMatchesTest( "TestExpansionModule/MultipleTestGenerationTest", test_name.GetString())) { all_tests_in_test_case_selected = false; } } EXPECT_TRUE(all_tests_in_test_case_selected) << "When running the TestGenerationTest test case all of its tests\n" << "must be selected by the filter flag for the test case to pass.\n" << "If not all of them are enabled, we can't reliably conclude\n" << "that the correct number of tests have been generated."; collected_parameters_.clear(); } static void TearDownTestCase() { vector expected_values(test_generation_params, test_generation_params + PARAMETER_COUNT); // Test execution order is not guaranteed by Google Test, // so the order of values in collected_parameters_ can be // different and we have to sort to compare. sort(expected_values.begin(), expected_values.end()); sort(collected_parameters_.begin(), collected_parameters_.end()); EXPECT_TRUE(collected_parameters_ == expected_values); } protected: int current_parameter_; static vector collected_parameters_; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest); }; vector TestGenerationTest::collected_parameters_; TEST_P(TestGenerationTest, TestsExpandedAndRun) { Environment::Instance()->TestBodyExecuted(); EXPECT_EQ(current_parameter_, GetParam()); collected_parameters_.push_back(GetParam()); } INSTANTIATE_TEST_CASE_P(TestExpansionModule, TestGenerationTest, ValuesIn(test_generation_params)); // This test verifies that the element sequence (third parameter of // INSTANTIATE_TEST_CASE_P) is evaluated in InitGoogleTest() and neither at // the call site of INSTANTIATE_TEST_CASE_P nor in RUN_ALL_TESTS(). For // that, we declare param_value_ to be a static member of // GeneratorEvaluationTest and initialize it to 0. We set it to 1 in // main(), just before invocation of InitGoogleTest(). After calling // InitGoogleTest(), we set the value to 2. If the sequence is evaluated // before or after InitGoogleTest, INSTANTIATE_TEST_CASE_P will create a // test with parameter other than 1, and the test body will fail the // assertion. class GeneratorEvaluationTest : public TestWithParam { public: static int param_value() { return param_value_; } static void set_param_value(int param_value) { param_value_ = param_value; } private: static int param_value_; }; int GeneratorEvaluationTest::param_value_ = 0; TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain) { EXPECT_EQ(1, GetParam()); } INSTANTIATE_TEST_CASE_P(GenEvalModule, GeneratorEvaluationTest, Values(GeneratorEvaluationTest::param_value())); // Tests that generators defined in a different translation unit are // functional. Generator extern_gen is defined in gtest-param-test_test2.cc. extern ParamGenerator extern_gen; class ExternalGeneratorTest : public TestWithParam {}; TEST_P(ExternalGeneratorTest, ExternalGenerator) { // Sequence produced by extern_gen contains only a single value // which we verify here. EXPECT_EQ(GetParam(), 33); } INSTANTIATE_TEST_CASE_P(ExternalGeneratorModule, ExternalGeneratorTest, extern_gen); // Tests that a parameterized test case can be defined in one translation // unit and instantiated in another. This test will be instantiated in // gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is // defined in gtest-param-test_test.h. TEST_P(ExternalInstantiationTest, IsMultipleOf33) { EXPECT_EQ(0, GetParam() % 33); } // Tests that a parameterized test case can be instantiated with multiple // generators. class MultipleInstantiationTest : public TestWithParam {}; TEST_P(MultipleInstantiationTest, AllowsMultipleInstances) { } INSTANTIATE_TEST_CASE_P(Sequence1, MultipleInstantiationTest, Values(1, 2)); INSTANTIATE_TEST_CASE_P(Sequence2, MultipleInstantiationTest, Range(3, 5)); // Tests that a parameterized test case can be instantiated // in multiple translation units. This test will be instantiated // here and in gtest-param-test_test2.cc. // InstantiationInMultipleTranslationUnitsTest fixture class // is defined in gtest-param-test_test.h. TEST_P(InstantiationInMultipleTranslaionUnitsTest, IsMultipleOf42) { EXPECT_EQ(0, GetParam() % 42); } INSTANTIATE_TEST_CASE_P(Sequence1, InstantiationInMultipleTranslaionUnitsTest, Values(42, 42*2)); // Tests that each iteration of parameterized test runs in a separate test // object. class SeparateInstanceTest : public TestWithParam { public: SeparateInstanceTest() : count_(0) {} static void TearDownTestCase() { EXPECT_GE(global_count_, 2) << "If some (but not all) SeparateInstanceTest tests have been " << "filtered out this test will fail. Make sure that all " << "GeneratorEvaluationTest are selected or de-selected together " << "by the test filter."; } protected: int count_; static int global_count_; }; int SeparateInstanceTest::global_count_ = 0; TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances) { EXPECT_EQ(0, count_++); global_count_++; } INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4)); // Tests that all instantiations of a test have named appropriately. Test // defined with TEST_P(TestCaseName, TestName) and instantiated with // INSTANTIATE_TEST_CASE_P(SequenceName, TestCaseName, generator) must be named // SequenceName/TestCaseName.TestName/i, where i is the 0-based index of the // sequence element used to instantiate the test. class NamingTest : public TestWithParam {}; TEST_P(NamingTest, TestsReportCorrectNamesAndParameters) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name()); Message index_stream; index_stream << "TestsReportCorrectNamesAndParameters/" << GetParam(); EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name()); EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); } INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5)); // Class that cannot be streamed into an ostream. It needs to be copyable // (and, in case of MSVC, also assignable) in order to be a test parameter // type. Its default copy constructor and assignment operator do exactly // what we need. class Unstreamable { public: explicit Unstreamable(int value) : value_(value) {} private: int value_; }; class CommentTest : public TestWithParam {}; TEST_P(CommentTest, TestsCorrectlyReportUnstreamableParams) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); } INSTANTIATE_TEST_CASE_P(InstantiationWithComments, CommentTest, Values(Unstreamable(1))); // Verify that we can create a hierarchy of test fixtures, where the base // class fixture is not parameterized and the derived class is. In this case // ParameterizedDerivedTest inherits from NonParameterizedBaseTest. We // perform simple tests on both. class NonParameterizedBaseTest : public ::testing::Test { public: NonParameterizedBaseTest() : n_(17) { } protected: int n_; }; class ParameterizedDerivedTest : public NonParameterizedBaseTest, public ::testing::WithParamInterface { protected: ParameterizedDerivedTest() : count_(0) { } int count_; static int global_count_; }; int ParameterizedDerivedTest::global_count_ = 0; TEST_F(NonParameterizedBaseTest, FixtureIsInitialized) { EXPECT_EQ(17, n_); } TEST_P(ParameterizedDerivedTest, SeesSequence) { EXPECT_EQ(17, n_); EXPECT_EQ(0, count_++); EXPECT_EQ(GetParam(), global_count_++); } class ParameterizedDeathTest : public ::testing::TestWithParam { }; TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) { EXPECT_DEATH_IF_SUPPORTED(GetParam(), ".* value-parameterized test .*"); } INSTANTIATE_TEST_CASE_P(RangeZeroToFive, ParameterizedDerivedTest, Range(0, 5)); #endif // GTEST_HAS_PARAM_TEST TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined) { #if GTEST_HAS_COMBINE && !GTEST_HAS_PARAM_TEST FAIL() << "GTEST_HAS_COMBINE is defined while GTEST_HAS_PARAM_TEST is not\n" #endif } int main(int argc, char **argv) { #if GTEST_HAS_PARAM_TEST // Used in TestGenerationTest test case. AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance()); // Used in GeneratorEvaluationTest test case. Tests that the updated value // will be picked up for instantiating tests in GeneratorEvaluationTest. GeneratorEvaluationTest::set_param_value(1); #endif // GTEST_HAS_PARAM_TEST ::testing::InitGoogleTest(&argc, argv); #if GTEST_HAS_PARAM_TEST // Used in GeneratorEvaluationTest test case. Tests that value updated // here will NOT be used for instantiating tests in // GeneratorEvaluationTest. GeneratorEvaluationTest::set_param_value(2); #endif // GTEST_HAS_PARAM_TEST return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-param-test_test.h000066400000000000000000000044471273231111400304700ustar00rootroot00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This header file provides classes and functions used internally // for testing Google Test itself. #ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ #define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ #include "gtest/gtest.h" #if GTEST_HAS_PARAM_TEST // Test fixture for testing definition and instantiation of a test // in separate translation units. class ExternalInstantiationTest : public ::testing::TestWithParam { }; // Test fixture for testing instantiation of a test in multiple // translation units. class InstantiationInMultipleTranslaionUnitsTest : public ::testing::TestWithParam { }; #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-port_test.cc000066400000000000000000001142661273231111400275360ustar00rootroot00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev), wan@google.com (Zhanyong Wan) // // This file tests the internal cross-platform support utilities. #include "gtest/internal/gtest-port.h" #include #if GTEST_OS_MAC # include #endif // GTEST_OS_MAC #include #include // For std::pair and std::make_pair. #include #include "gtest/gtest.h" #include "gtest/gtest-spi.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_ using std::make_pair; using std::pair; namespace testing { namespace internal { TEST(IsXDigitTest, WorksForNarrowAscii) { EXPECT_TRUE(IsXDigit('0')); EXPECT_TRUE(IsXDigit('9')); EXPECT_TRUE(IsXDigit('A')); EXPECT_TRUE(IsXDigit('F')); EXPECT_TRUE(IsXDigit('a')); EXPECT_TRUE(IsXDigit('f')); EXPECT_FALSE(IsXDigit('-')); EXPECT_FALSE(IsXDigit('g')); EXPECT_FALSE(IsXDigit('G')); } TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii) { EXPECT_FALSE(IsXDigit(static_cast(0x80))); EXPECT_FALSE(IsXDigit(static_cast('0' | 0x80))); } TEST(IsXDigitTest, WorksForWideAscii) { EXPECT_TRUE(IsXDigit(L'0')); EXPECT_TRUE(IsXDigit(L'9')); EXPECT_TRUE(IsXDigit(L'A')); EXPECT_TRUE(IsXDigit(L'F')); EXPECT_TRUE(IsXDigit(L'a')); EXPECT_TRUE(IsXDigit(L'f')); EXPECT_FALSE(IsXDigit(L'-')); EXPECT_FALSE(IsXDigit(L'g')); EXPECT_FALSE(IsXDigit(L'G')); } TEST(IsXDigitTest, ReturnsFalseForWideNonAscii) { EXPECT_FALSE(IsXDigit(static_cast(0x80))); EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x80))); EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x100))); } class Base { public: // Copy constructor and assignment operator do exactly what we need, so we // use them. Base() : member_(0) {} explicit Base(int n) : member_(n) {} virtual ~Base() {} int member() { return member_; } private: int member_; }; class Derived : public Base { public: explicit Derived(int n) : Base(n) {} }; TEST(ImplicitCastTest, ConvertsPointers) { Derived derived(0); EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_(&derived)); } TEST(ImplicitCastTest, CanUseInheritance) { Derived derived(1); Base base = ::testing::internal::ImplicitCast_(derived); EXPECT_EQ(derived.member(), base.member()); } class Castable { public: explicit Castable(bool* converted) : converted_(converted) {} operator Base() { *converted_ = true; return Base(); } private: bool* converted_; }; TEST(ImplicitCastTest, CanUseNonConstCastOperator) { bool converted = false; Castable castable(&converted); Base base = ::testing::internal::ImplicitCast_(castable); EXPECT_TRUE(converted); } class ConstCastable { public: explicit ConstCastable(bool* converted) : converted_(converted) {} operator Base() const { *converted_ = true; return Base(); } private: bool* converted_; }; TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { bool converted = false; const ConstCastable const_castable(&converted); Base base = ::testing::internal::ImplicitCast_(const_castable); EXPECT_TRUE(converted); } class ConstAndNonConstCastable { public: ConstAndNonConstCastable(bool* converted, bool* const_converted) : converted_(converted), const_converted_(const_converted) {} operator Base() { *converted_ = true; return Base(); } operator Base() const { *const_converted_ = true; return Base(); } private: bool* converted_; bool* const_converted_; }; TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { bool converted = false; bool const_converted = false; ConstAndNonConstCastable castable(&converted, &const_converted); Base base = ::testing::internal::ImplicitCast_(castable); EXPECT_TRUE(converted); EXPECT_FALSE(const_converted); converted = false; const_converted = false; const ConstAndNonConstCastable const_castable(&converted, &const_converted); base = ::testing::internal::ImplicitCast_(const_castable); EXPECT_FALSE(converted); EXPECT_TRUE(const_converted); } class To { public: To(bool* converted) { *converted = true; } // NOLINT }; TEST(ImplicitCastTest, CanUseImplicitConstructor) { bool converted = false; To to = ::testing::internal::ImplicitCast_(&converted); (void)to; EXPECT_TRUE(converted); } TEST(IteratorTraitsTest, WorksForSTLContainerIterators) { StaticAssertTypeEq::const_iterator>::value_type>(); StaticAssertTypeEq::iterator>::value_type>(); } TEST(IteratorTraitsTest, WorksForPointerToNonConst) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); } TEST(IteratorTraitsTest, WorksForPointerToConst) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); } // Tests that the element_type typedef is available in scoped_ptr and refers // to the parameter type. TEST(ScopedPtrTest, DefinesElementType) { StaticAssertTypeEq::element_type>(); } // TODO(vladl@google.com): Implement THE REST of scoped_ptr tests. TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { if (AlwaysFalse()) GTEST_CHECK_(false) << "This should never be executed; " "It's a compilation test only."; if (AlwaysTrue()) GTEST_CHECK_(true); else ; // NOLINT if (AlwaysFalse()) ; // NOLINT else GTEST_CHECK_(true) << ""; } TEST(GtestCheckSyntaxTest, WorksWithSwitch) { switch (0) { case 1: break; default: GTEST_CHECK_(true); } switch (0) case 0: GTEST_CHECK_(true) << "Check failed in switch case"; } // Verifies behavior of FormatFileLocation. TEST(FormatFileLocationTest, FormatsFileLocation) { EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); } TEST(FormatFileLocationTest, FormatsUnknownFile) { EXPECT_PRED_FORMAT2( IsSubstring, "unknown file", FormatFileLocation(NULL, 42)); EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(NULL, 42)); } TEST(FormatFileLocationTest, FormatsUknownLine) { EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1)); } TEST(FormatFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file:", FormatFileLocation(NULL, -1)); } // Verifies behavior of FormatCompilerIndependentFileLocation. TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation) { EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile) { EXPECT_EQ("unknown file:42", FormatCompilerIndependentFileLocation(NULL, 42)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1)); } #if GTEST_OS_MAC || GTEST_OS_QNX void* ThreadFunc(void* data) { pthread_mutex_t* mutex = static_cast(data); pthread_mutex_lock(mutex); pthread_mutex_unlock(mutex); return NULL; } TEST(GetThreadCountTest, ReturnsCorrectValue) { EXPECT_EQ(1U, GetThreadCount()); pthread_mutex_t mutex; pthread_attr_t attr; pthread_t thread_id; // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic // destruction. pthread_mutex_init(&mutex, NULL); pthread_mutex_lock(&mutex); ASSERT_EQ(0, pthread_attr_init(&attr)); ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); ASSERT_EQ(0, pthread_attr_destroy(&attr)); ASSERT_EQ(0, status); EXPECT_EQ(2U, GetThreadCount()); pthread_mutex_unlock(&mutex); void* dummy; ASSERT_EQ(0, pthread_join(thread_id, &dummy)); # if GTEST_OS_MAC // MacOS X may not immediately report the updated thread count after // joining a thread, causing flakiness in this test. To counter that, we // wait for up to .5 seconds for the OS to report the correct value. for (int i = 0; i < 5; ++i) { if (GetThreadCount() == 1) break; SleepMilliseconds(100); } # endif // GTEST_OS_MAC EXPECT_EQ(1U, GetThreadCount()); pthread_mutex_destroy(&mutex); } #else TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { EXPECT_EQ(0U, GetThreadCount()); } #endif // GTEST_OS_MAC || GTEST_OS_QNX TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; const char regex[] = #ifdef _MSC_VER "gtest-port_test\\.cc\\(\\d+\\):" #elif GTEST_USES_POSIX_RE "gtest-port_test\\.cc:[0-9]+" #else "gtest-port_test\\.cc:\\d+" #endif // _MSC_VER ".*a_false_condition.*Extra info.*"; EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", regex); } #if GTEST_HAS_DEATH_TEST TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { EXPECT_EXIT({ GTEST_CHECK_(true) << "Extra info"; ::std::cerr << "Success\n"; exit(0); }, ::testing::ExitedWithCode(0), "Success"); } #endif // GTEST_HAS_DEATH_TEST // Verifies that Google Test choose regular expression engine appropriate to // the platform. The test will produce compiler errors in case of failure. // For simplicity, we only cover the most important platforms here. TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { #if GTEST_HAS_POSIX_RE EXPECT_TRUE(GTEST_USES_POSIX_RE); #else EXPECT_TRUE(GTEST_USES_SIMPLE_RE); #endif } #if GTEST_USES_POSIX_RE # if GTEST_HAS_TYPED_TEST template class RETest : public ::testing::Test {}; // Defines StringTypes as the list of all string types that class RE // supports. typedef testing::Types< ::std::string, # if GTEST_HAS_GLOBAL_STRING ::string, # endif // GTEST_HAS_GLOBAL_STRING const char*> StringTypes; TYPED_TEST_CASE(RETest, StringTypes); // Tests RE's implicit constructors. TYPED_TEST(RETest, ImplicitConstructorWorks) { const RE empty(TypeParam("")); EXPECT_STREQ("", empty.pattern()); const RE simple(TypeParam("hello")); EXPECT_STREQ("hello", simple.pattern()); const RE normal(TypeParam(".*(\\w+)")); EXPECT_STREQ(".*(\\w+)", normal.pattern()); } // Tests that RE's constructors reject invalid regular expressions. TYPED_TEST(RETest, RejectsInvalidRegex) { EXPECT_NONFATAL_FAILURE({ const RE invalid(TypeParam("?")); }, "\"?\" is not a valid POSIX Extended regular expression."); } // Tests RE::FullMatch(). TYPED_TEST(RETest, FullMatchWorks) { const RE empty(TypeParam("")); EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); const RE re(TypeParam("a.*z")); EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re)); EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re)); EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re)); } // Tests RE::PartialMatch(). TYPED_TEST(RETest, PartialMatchWorks) { const RE empty(TypeParam("")); EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty)); EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty)); const RE re(TypeParam("a.*z")); EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re)); EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re)); EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re)); } # endif // GTEST_HAS_TYPED_TEST #elif GTEST_USES_SIMPLE_RE TEST(IsInSetTest, NulCharIsNotInAnySet) { EXPECT_FALSE(IsInSet('\0', "")); EXPECT_FALSE(IsInSet('\0', "\0")); EXPECT_FALSE(IsInSet('\0', "a")); } TEST(IsInSetTest, WorksForNonNulChars) { EXPECT_FALSE(IsInSet('a', "Ab")); EXPECT_FALSE(IsInSet('c', "")); EXPECT_TRUE(IsInSet('b', "bcd")); EXPECT_TRUE(IsInSet('b', "ab")); } TEST(IsAsciiDigitTest, IsFalseForNonDigit) { EXPECT_FALSE(IsAsciiDigit('\0')); EXPECT_FALSE(IsAsciiDigit(' ')); EXPECT_FALSE(IsAsciiDigit('+')); EXPECT_FALSE(IsAsciiDigit('-')); EXPECT_FALSE(IsAsciiDigit('.')); EXPECT_FALSE(IsAsciiDigit('a')); } TEST(IsAsciiDigitTest, IsTrueForDigit) { EXPECT_TRUE(IsAsciiDigit('0')); EXPECT_TRUE(IsAsciiDigit('1')); EXPECT_TRUE(IsAsciiDigit('5')); EXPECT_TRUE(IsAsciiDigit('9')); } TEST(IsAsciiPunctTest, IsFalseForNonPunct) { EXPECT_FALSE(IsAsciiPunct('\0')); EXPECT_FALSE(IsAsciiPunct(' ')); EXPECT_FALSE(IsAsciiPunct('\n')); EXPECT_FALSE(IsAsciiPunct('a')); EXPECT_FALSE(IsAsciiPunct('0')); } TEST(IsAsciiPunctTest, IsTrueForPunct) { for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { EXPECT_PRED1(IsAsciiPunct, *p); } } TEST(IsRepeatTest, IsFalseForNonRepeatChar) { EXPECT_FALSE(IsRepeat('\0')); EXPECT_FALSE(IsRepeat(' ')); EXPECT_FALSE(IsRepeat('a')); EXPECT_FALSE(IsRepeat('1')); EXPECT_FALSE(IsRepeat('-')); } TEST(IsRepeatTest, IsTrueForRepeatChar) { EXPECT_TRUE(IsRepeat('?')); EXPECT_TRUE(IsRepeat('*')); EXPECT_TRUE(IsRepeat('+')); } TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) { EXPECT_FALSE(IsAsciiWhiteSpace('\0')); EXPECT_FALSE(IsAsciiWhiteSpace('a')); EXPECT_FALSE(IsAsciiWhiteSpace('1')); EXPECT_FALSE(IsAsciiWhiteSpace('+')); EXPECT_FALSE(IsAsciiWhiteSpace('_')); } TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) { EXPECT_TRUE(IsAsciiWhiteSpace(' ')); EXPECT_TRUE(IsAsciiWhiteSpace('\n')); EXPECT_TRUE(IsAsciiWhiteSpace('\r')); EXPECT_TRUE(IsAsciiWhiteSpace('\t')); EXPECT_TRUE(IsAsciiWhiteSpace('\v')); EXPECT_TRUE(IsAsciiWhiteSpace('\f')); } TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) { EXPECT_FALSE(IsAsciiWordChar('\0')); EXPECT_FALSE(IsAsciiWordChar('+')); EXPECT_FALSE(IsAsciiWordChar('.')); EXPECT_FALSE(IsAsciiWordChar(' ')); EXPECT_FALSE(IsAsciiWordChar('\n')); } TEST(IsAsciiWordCharTest, IsTrueForLetter) { EXPECT_TRUE(IsAsciiWordChar('a')); EXPECT_TRUE(IsAsciiWordChar('b')); EXPECT_TRUE(IsAsciiWordChar('A')); EXPECT_TRUE(IsAsciiWordChar('Z')); } TEST(IsAsciiWordCharTest, IsTrueForDigit) { EXPECT_TRUE(IsAsciiWordChar('0')); EXPECT_TRUE(IsAsciiWordChar('1')); EXPECT_TRUE(IsAsciiWordChar('7')); EXPECT_TRUE(IsAsciiWordChar('9')); } TEST(IsAsciiWordCharTest, IsTrueForUnderscore) { EXPECT_TRUE(IsAsciiWordChar('_')); } TEST(IsValidEscapeTest, IsFalseForNonPrintable) { EXPECT_FALSE(IsValidEscape('\0')); EXPECT_FALSE(IsValidEscape('\007')); } TEST(IsValidEscapeTest, IsFalseForDigit) { EXPECT_FALSE(IsValidEscape('0')); EXPECT_FALSE(IsValidEscape('9')); } TEST(IsValidEscapeTest, IsFalseForWhiteSpace) { EXPECT_FALSE(IsValidEscape(' ')); EXPECT_FALSE(IsValidEscape('\n')); } TEST(IsValidEscapeTest, IsFalseForSomeLetter) { EXPECT_FALSE(IsValidEscape('a')); EXPECT_FALSE(IsValidEscape('Z')); } TEST(IsValidEscapeTest, IsTrueForPunct) { EXPECT_TRUE(IsValidEscape('.')); EXPECT_TRUE(IsValidEscape('-')); EXPECT_TRUE(IsValidEscape('^')); EXPECT_TRUE(IsValidEscape('$')); EXPECT_TRUE(IsValidEscape('(')); EXPECT_TRUE(IsValidEscape(']')); EXPECT_TRUE(IsValidEscape('{')); EXPECT_TRUE(IsValidEscape('|')); } TEST(IsValidEscapeTest, IsTrueForSomeLetter) { EXPECT_TRUE(IsValidEscape('d')); EXPECT_TRUE(IsValidEscape('D')); EXPECT_TRUE(IsValidEscape('s')); EXPECT_TRUE(IsValidEscape('S')); EXPECT_TRUE(IsValidEscape('w')); EXPECT_TRUE(IsValidEscape('W')); } TEST(AtomMatchesCharTest, EscapedPunct) { EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0')); EXPECT_FALSE(AtomMatchesChar(true, '\\', ' ')); EXPECT_FALSE(AtomMatchesChar(true, '_', '.')); EXPECT_FALSE(AtomMatchesChar(true, '.', 'a')); EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\')); EXPECT_TRUE(AtomMatchesChar(true, '_', '_')); EXPECT_TRUE(AtomMatchesChar(true, '+', '+')); EXPECT_TRUE(AtomMatchesChar(true, '.', '.')); } TEST(AtomMatchesCharTest, Escaped_d) { EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 'd', '.')); EXPECT_TRUE(AtomMatchesChar(true, 'd', '0')); EXPECT_TRUE(AtomMatchesChar(true, 'd', '9')); } TEST(AtomMatchesCharTest, Escaped_D) { EXPECT_FALSE(AtomMatchesChar(true, 'D', '0')); EXPECT_FALSE(AtomMatchesChar(true, 'D', '9')); EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a')); EXPECT_TRUE(AtomMatchesChar(true, 'D', '-')); } TEST(AtomMatchesCharTest, Escaped_s) { EXPECT_FALSE(AtomMatchesChar(true, 's', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 's', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 's', '.')); EXPECT_FALSE(AtomMatchesChar(true, 's', '9')); EXPECT_TRUE(AtomMatchesChar(true, 's', ' ')); EXPECT_TRUE(AtomMatchesChar(true, 's', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 's', '\t')); } TEST(AtomMatchesCharTest, Escaped_S) { EXPECT_FALSE(AtomMatchesChar(true, 'S', ' ')); EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r')); EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a')); EXPECT_TRUE(AtomMatchesChar(true, 'S', '9')); } TEST(AtomMatchesCharTest, Escaped_w) { EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'w', '+')); EXPECT_FALSE(AtomMatchesChar(true, 'w', ' ')); EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 'w', '0')); EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b')); EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C')); EXPECT_TRUE(AtomMatchesChar(true, 'w', '_')); } TEST(AtomMatchesCharTest, Escaped_W) { EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A')); EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b')); EXPECT_FALSE(AtomMatchesChar(true, 'W', '9')); EXPECT_FALSE(AtomMatchesChar(true, 'W', '_')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '*')); EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n')); } TEST(AtomMatchesCharTest, EscapedWhiteSpace) { EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n')); EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r')); EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a')); EXPECT_FALSE(AtomMatchesChar(true, 't', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 't', 't')); EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0')); EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f')); EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f')); EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n')); EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r')); EXPECT_TRUE(AtomMatchesChar(true, 't', '\t')); EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v')); } TEST(AtomMatchesCharTest, UnescapedDot) { EXPECT_FALSE(AtomMatchesChar(false, '.', '\n')); EXPECT_TRUE(AtomMatchesChar(false, '.', '\0')); EXPECT_TRUE(AtomMatchesChar(false, '.', '.')); EXPECT_TRUE(AtomMatchesChar(false, '.', 'a')); EXPECT_TRUE(AtomMatchesChar(false, '.', ' ')); } TEST(AtomMatchesCharTest, UnescapedChar) { EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0')); EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b')); EXPECT_FALSE(AtomMatchesChar(false, '$', 'a')); EXPECT_TRUE(AtomMatchesChar(false, '$', '$')); EXPECT_TRUE(AtomMatchesChar(false, '5', '5')); EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z')); } TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) { EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)), "NULL is not a valid simple regular expression"); EXPECT_NONFATAL_FAILURE( ASSERT_FALSE(ValidateRegex("a\\")), "Syntax error at index 1 in simple regular expression \"a\\\": "); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")), "'\\' cannot appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")), "'\\' cannot appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")), "invalid escape sequence \"\\h\""); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")), "'^' can only appear at the beginning"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")), "'^' can only appear at the beginning"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")), "'$' can only appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")), "'$' can only appear at the end"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")), "'(' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")), "')' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")), "'[' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")), "'{' is unsupported"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")), "'?' can only follow a repeatable token"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")), "'*' can only follow a repeatable token"); EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")), "'+' can only follow a repeatable token"); } TEST(ValidateRegexTest, ReturnsTrueForValid) { EXPECT_TRUE(ValidateRegex("")); EXPECT_TRUE(ValidateRegex("a")); EXPECT_TRUE(ValidateRegex(".*")); EXPECT_TRUE(ValidateRegex("^a_+")); EXPECT_TRUE(ValidateRegex("^a\\t\\&?")); EXPECT_TRUE(ValidateRegex("09*$")); EXPECT_TRUE(ValidateRegex("^Z$")); EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba")); // Repeating more than once. EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab")); // Repeating zero times. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab")); EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab")); // Repeating zero times. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc")); // Repeating more than once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g")); } TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) { EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab")); // Repeating zero times. EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc")); // Repeating once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc")); // Repeating more than once. EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g")); } TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) { EXPECT_TRUE(MatchRegexAtHead("", "")); EXPECT_TRUE(MatchRegexAtHead("", "ab")); } TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) { EXPECT_FALSE(MatchRegexAtHead("$", "a")); EXPECT_TRUE(MatchRegexAtHead("$", "")); EXPECT_TRUE(MatchRegexAtHead("a$", "a")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) { EXPECT_FALSE(MatchRegexAtHead("\\w", "+")); EXPECT_FALSE(MatchRegexAtHead("\\W", "ab")); EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab")); EXPECT_TRUE(MatchRegexAtHead("\\d", "1a")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); } TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetionOfEscapeSequence) { EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); } TEST(MatchRegexAtHeadTest, MatchesSequentially) { EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc")); EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc")); } TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) { EXPECT_FALSE(MatchRegexAnywhere("", NULL)); } TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) { EXPECT_FALSE(MatchRegexAnywhere("^a", "ba")); EXPECT_FALSE(MatchRegexAnywhere("^$", "a")); EXPECT_TRUE(MatchRegexAnywhere("^a", "ab")); EXPECT_TRUE(MatchRegexAnywhere("^", "ab")); EXPECT_TRUE(MatchRegexAnywhere("^$", "")); } TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) { EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123")); EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888")); } TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) { EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5")); EXPECT_TRUE(MatchRegexAnywhere(".*=", "=")); EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc")); } TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) { EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5")); EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...=")); } // Tests RE's implicit constructors. TEST(RETest, ImplicitConstructorWorks) { const RE empty(""); EXPECT_STREQ("", empty.pattern()); const RE simple("hello"); EXPECT_STREQ("hello", simple.pattern()); } // Tests that RE's constructors reject invalid regular expressions. TEST(RETest, RejectsInvalidRegex) { EXPECT_NONFATAL_FAILURE({ const RE normal(NULL); }, "NULL is not a valid simple regular expression"); EXPECT_NONFATAL_FAILURE({ const RE normal(".*(\\w+"); }, "'(' is unsupported"); EXPECT_NONFATAL_FAILURE({ const RE invalid("^?"); }, "'?' can only follow a repeatable token"); } // Tests RE::FullMatch(). TEST(RETest, FullMatchWorks) { const RE empty(""); EXPECT_TRUE(RE::FullMatch("", empty)); EXPECT_FALSE(RE::FullMatch("a", empty)); const RE re1("a"); EXPECT_TRUE(RE::FullMatch("a", re1)); const RE re("a.*z"); EXPECT_TRUE(RE::FullMatch("az", re)); EXPECT_TRUE(RE::FullMatch("axyz", re)); EXPECT_FALSE(RE::FullMatch("baz", re)); EXPECT_FALSE(RE::FullMatch("azy", re)); } // Tests RE::PartialMatch(). TEST(RETest, PartialMatchWorks) { const RE empty(""); EXPECT_TRUE(RE::PartialMatch("", empty)); EXPECT_TRUE(RE::PartialMatch("a", empty)); const RE re("a.*z"); EXPECT_TRUE(RE::PartialMatch("az", re)); EXPECT_TRUE(RE::PartialMatch("axyz", re)); EXPECT_TRUE(RE::PartialMatch("baz", re)); EXPECT_TRUE(RE::PartialMatch("azy", re)); EXPECT_FALSE(RE::PartialMatch("zza", re)); } #endif // GTEST_USES_POSIX_RE #if !GTEST_OS_WINDOWS_MOBILE TEST(CaptureTest, CapturesStdout) { CaptureStdout(); fprintf(stdout, "abc"); EXPECT_STREQ("abc", GetCapturedStdout().c_str()); CaptureStdout(); fprintf(stdout, "def%cghi", '\0'); EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout())); } TEST(CaptureTest, CapturesStderr) { CaptureStderr(); fprintf(stderr, "jkl"); EXPECT_STREQ("jkl", GetCapturedStderr().c_str()); CaptureStderr(); fprintf(stderr, "jkl%cmno", '\0'); EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr())); } // Tests that stdout and stderr capture don't interfere with each other. TEST(CaptureTest, CapturesStdoutAndStderr) { CaptureStdout(); CaptureStderr(); fprintf(stdout, "pqr"); fprintf(stderr, "stu"); EXPECT_STREQ("pqr", GetCapturedStdout().c_str()); EXPECT_STREQ("stu", GetCapturedStderr().c_str()); } TEST(CaptureDeathTest, CannotReenterStdoutCapture) { CaptureStdout(); EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(), "Only one stdout capturer can exist at a time"); GetCapturedStdout(); // We cannot test stderr capturing using death tests as they use it // themselves. } #endif // !GTEST_OS_WINDOWS_MOBILE TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) { ThreadLocal t1; EXPECT_EQ(0, t1.get()); ThreadLocal t2; EXPECT_TRUE(t2.get() == NULL); } TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { ThreadLocal t1(123); EXPECT_EQ(123, t1.get()); int i = 0; ThreadLocal t2(&i); EXPECT_EQ(&i, t2.get()); } class NoDefaultContructor { public: explicit NoDefaultContructor(const char*) {} NoDefaultContructor(const NoDefaultContructor&) {} }; TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { ThreadLocal bar(NoDefaultContructor("foo")); bar.pointer(); } TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { ThreadLocal thread_local_string; EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); // Verifies the condition still holds after calling set. thread_local_string.set("foo"); EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); } TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { ThreadLocal thread_local_string; const ThreadLocal& const_thread_local_string = thread_local_string; EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); thread_local_string.set("foo"); EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); } #if GTEST_IS_THREADSAFE void AddTwo(int* param) { *param += 2; } TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { int i = 40; ThreadWithParam thread(&AddTwo, &i, NULL); thread.Join(); EXPECT_EQ(42, i); } TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { // AssertHeld() is flaky only in the presence of multiple threads accessing // the lock. In this case, the test is robust. EXPECT_DEATH_IF_SUPPORTED({ Mutex m; { MutexLock lock(&m); } m.AssertHeld(); }, "thread .*hold"); } TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { Mutex m; MutexLock lock(&m); m.AssertHeld(); } class AtomicCounterWithMutex { public: explicit AtomicCounterWithMutex(Mutex* mutex) : value_(0), mutex_(mutex), random_(42) {} void Increment() { MutexLock lock(mutex_); int temp = value_; { // Locking a mutex puts up a memory barrier, preventing reads and // writes to value_ rearranged when observed from other threads. // // We cannot use Mutex and MutexLock here or rely on their memory // barrier functionality as we are testing them here. pthread_mutex_t memory_barrier_mutex; GTEST_CHECK_POSIX_SUCCESS_( pthread_mutex_init(&memory_barrier_mutex, NULL)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); SleepMilliseconds(random_.Generate(30)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); } value_ = temp + 1; } int value() const { return value_; } private: volatile int value_; Mutex* const mutex_; // Protects value_. Random random_; }; void CountingThreadFunc(pair param) { for (int i = 0; i < param.second; ++i) param.first->Increment(); } // Tests that the mutex only lets one thread at a time to lock it. TEST(MutexTest, OnlyOneThreadCanLockAtATime) { Mutex mutex; AtomicCounterWithMutex locked_counter(&mutex); typedef ThreadWithParam > ThreadType; const int kCycleCount = 20; const int kThreadCount = 7; scoped_ptr counting_threads[kThreadCount]; Notification threads_can_start; // Creates and runs kThreadCount threads that increment locked_counter // kCycleCount times each. for (int i = 0; i < kThreadCount; ++i) { counting_threads[i].reset(new ThreadType(&CountingThreadFunc, make_pair(&locked_counter, kCycleCount), &threads_can_start)); } threads_can_start.Notify(); for (int i = 0; i < kThreadCount; ++i) counting_threads[i]->Join(); // If the mutex lets more than one thread to increment the counter at a // time, they are likely to encounter a race condition and have some // increments overwritten, resulting in the lower then expected counter // value. EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); } template void RunFromThread(void (func)(T), T param) { ThreadWithParam thread(func, param, NULL); thread.Join(); } void RetrieveThreadLocalValue( pair*, std::string*> param) { *param.second = param.first->get(); } TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { ThreadLocal thread_local_string("foo"); EXPECT_STREQ("foo", thread_local_string.get().c_str()); thread_local_string.set("bar"); EXPECT_STREQ("bar", thread_local_string.get().c_str()); std::string result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local_string, &result)); EXPECT_STREQ("foo", result.c_str()); } // DestructorTracker keeps track of whether its instances have been // destroyed. static std::vector g_destroyed; class DestructorTracker { public: DestructorTracker() : index_(GetNewIndex()) {} DestructorTracker(const DestructorTracker& /* rhs */) : index_(GetNewIndex()) {} ~DestructorTracker() { // We never access g_destroyed concurrently, so we don't need to // protect the write operation under a mutex. g_destroyed[index_] = true; } private: static int GetNewIndex() { g_destroyed.push_back(false); return g_destroyed.size() - 1; } const int index_; }; typedef ThreadLocal* ThreadParam; void CallThreadLocalGet(ThreadParam thread_local_param) { thread_local_param->get(); } // Tests that when a ThreadLocal object dies in a thread, it destroys // the managed object for that thread. TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { g_destroyed.clear(); { // The next line default constructs a DestructorTracker object as // the default value of objects managed by thread_local_tracker. ThreadLocal thread_local_tracker; ASSERT_EQ(1U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); // This creates another DestructorTracker object for the main thread. thread_local_tracker.get(); ASSERT_EQ(2U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); ASSERT_FALSE(g_destroyed[1]); } // Now thread_local_tracker has died. It should have destroyed both the // default value shared by all threads and the value for the main // thread. ASSERT_EQ(2U, g_destroyed.size()); EXPECT_TRUE(g_destroyed[0]); EXPECT_TRUE(g_destroyed[1]); g_destroyed.clear(); } // Tests that when a thread exits, the thread-local object for that // thread is destroyed. TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { g_destroyed.clear(); { // The next line default constructs a DestructorTracker object as // the default value of objects managed by thread_local_tracker. ThreadLocal thread_local_tracker; ASSERT_EQ(1U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); // This creates another DestructorTracker object in the new thread. ThreadWithParam thread( &CallThreadLocalGet, &thread_local_tracker, NULL); thread.Join(); // Now the new thread has exited. The per-thread object for it // should have been destroyed. ASSERT_EQ(2U, g_destroyed.size()); ASSERT_FALSE(g_destroyed[0]); ASSERT_TRUE(g_destroyed[1]); } // Now thread_local_tracker has died. The default value should have been // destroyed too. ASSERT_EQ(2U, g_destroyed.size()); EXPECT_TRUE(g_destroyed[0]); EXPECT_TRUE(g_destroyed[1]); g_destroyed.clear(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { ThreadLocal thread_local_string; thread_local_string.set("Foo"); EXPECT_STREQ("Foo", thread_local_string.get().c_str()); std::string result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local_string, &result)); EXPECT_TRUE(result.empty()); } #endif // GTEST_IS_THREADSAFE } // namespace internal } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-printers_test.cc000066400000000000000000001406641273231111400304210ustar00rootroot00000000000000// 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 tests the universal value printer. #include "gtest/gtest-printers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "gtest/gtest.h" // hash_map and hash_set are available under Visual C++. #if _MSC_VER # define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. # include // NOLINT # define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. # include // NOLINT #endif // GTEST_OS_WINDOWS // Some user-defined types for testing the universal value printer. // An anonymous enum type. enum AnonymousEnum { kAE1 = -1, kAE2 = 1 }; // An enum without a user-defined printer. enum EnumWithoutPrinter { kEWP1 = -2, kEWP2 = 42 }; // An enum with a << operator. enum EnumWithStreaming { kEWS1 = 10 }; std::ostream& operator<<(std::ostream& os, EnumWithStreaming e) { return os << (e == kEWS1 ? "kEWS1" : "invalid"); } // An enum with a PrintTo() function. enum EnumWithPrintTo { kEWPT1 = 1 }; void PrintTo(EnumWithPrintTo e, std::ostream* os) { *os << (e == kEWPT1 ? "kEWPT1" : "invalid"); } // A class implicitly convertible to BiggestInt. class BiggestIntConvertible { public: operator ::testing::internal::BiggestInt() const { return 42; } }; // A user-defined unprintable class template in the global namespace. template class UnprintableTemplateInGlobal { public: UnprintableTemplateInGlobal() : value_() {} private: T value_; }; // A user-defined streamable type in the global namespace. class StreamableInGlobal { public: virtual ~StreamableInGlobal() {} }; inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { os << "StreamableInGlobal"; } void operator<<(::std::ostream& os, const StreamableInGlobal* /* x */) { os << "StreamableInGlobal*"; } namespace foo { // A user-defined unprintable type in a user namespace. class UnprintableInFoo { public: UnprintableInFoo() : z_(0) { memcpy(xy_, "\xEF\x12\x0\x0\x34\xAB\x0\x0", 8); } private: char xy_[8]; double z_; }; // A user-defined printable type in a user-chosen namespace. struct PrintableViaPrintTo { PrintableViaPrintTo() : value() {} int value; }; void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { *os << "PrintableViaPrintTo: " << x.value; } // A type with a user-defined << for printing its pointer. struct PointerPrintable { }; ::std::ostream& operator<<(::std::ostream& os, const PointerPrintable* /* x */) { return os << "PointerPrintable*"; } // A user-defined printable class template in a user-chosen namespace. template class PrintableViaPrintToTemplate { public: explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} const T& value() const { return value_; } private: T value_; }; template void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { *os << "PrintableViaPrintToTemplate: " << x.value(); } // A user-defined streamable class template in a user namespace. template class StreamableTemplateInFoo { public: StreamableTemplateInFoo() : value_() {} const T& value() const { return value_; } private: T value_; }; template inline ::std::ostream& operator<<(::std::ostream& os, const StreamableTemplateInFoo& x) { return os << "StreamableTemplateInFoo: " << x.value(); } } // namespace foo namespace testing { namespace gtest_printers_test { using ::std::deque; using ::std::list; using ::std::make_pair; using ::std::map; using ::std::multimap; using ::std::multiset; using ::std::pair; using ::std::set; using ::std::vector; using ::testing::PrintToString; using ::testing::internal::FormatForComparisonFailureMessage; using ::testing::internal::ImplicitCast_; using ::testing::internal::NativeArray; using ::testing::internal::RE; using ::testing::internal::Strings; using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalPrinter; using ::testing::internal::UniversalTersePrint; using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; using ::testing::internal::kReference; using ::testing::internal::string; #if GTEST_HAS_TR1_TUPLE using ::std::tr1::make_tuple; using ::std::tr1::tuple; #endif // The hash_* classes are not part of the C++ standard. STLport // defines them in namespace std. MSVC defines them in ::stdext. GCC // defines them in ::. #ifdef _STLP_HASH_MAP // We got from STLport. using ::std::hash_map; using ::std::hash_set; using ::std::hash_multimap; using ::std::hash_multiset; #elif _MSC_VER using ::stdext::hash_map; using ::stdext::hash_set; using ::stdext::hash_multimap; using ::stdext::hash_multiset; #endif // Prints a value to a string using the universal value printer. This // is a helper for testing UniversalPrinter::Print() for various types. template string Print(const T& value) { ::std::stringstream ss; UniversalPrinter::Print(value, &ss); return ss.str(); } // Prints a value passed by reference to a string, using the universal // value printer. This is a helper for testing // UniversalPrinter::Print() for various types. template string PrintByRef(const T& value) { ::std::stringstream ss; UniversalPrinter::Print(value, &ss); return ss.str(); } // Tests printing various enum types. TEST(PrintEnumTest, AnonymousEnum) { EXPECT_EQ("-1", Print(kAE1)); EXPECT_EQ("1", Print(kAE2)); } TEST(PrintEnumTest, EnumWithoutPrinter) { EXPECT_EQ("-2", Print(kEWP1)); EXPECT_EQ("42", Print(kEWP2)); } TEST(PrintEnumTest, EnumWithStreaming) { EXPECT_EQ("kEWS1", Print(kEWS1)); EXPECT_EQ("invalid", Print(static_cast(0))); } TEST(PrintEnumTest, EnumWithPrintTo) { EXPECT_EQ("kEWPT1", Print(kEWPT1)); EXPECT_EQ("invalid", Print(static_cast(0))); } // Tests printing a class implicitly convertible to BiggestInt. TEST(PrintClassTest, BiggestIntConvertible) { EXPECT_EQ("42", Print(BiggestIntConvertible())); } // Tests printing various char types. // char. TEST(PrintCharTest, PlainChar) { EXPECT_EQ("'\\0'", Print('\0')); EXPECT_EQ("'\\'' (39, 0x27)", Print('\'')); EXPECT_EQ("'\"' (34, 0x22)", Print('"')); EXPECT_EQ("'?' (63, 0x3F)", Print('?')); EXPECT_EQ("'\\\\' (92, 0x5C)", Print('\\')); EXPECT_EQ("'\\a' (7)", Print('\a')); EXPECT_EQ("'\\b' (8)", Print('\b')); EXPECT_EQ("'\\f' (12, 0xC)", Print('\f')); EXPECT_EQ("'\\n' (10, 0xA)", Print('\n')); EXPECT_EQ("'\\r' (13, 0xD)", Print('\r')); EXPECT_EQ("'\\t' (9)", Print('\t')); EXPECT_EQ("'\\v' (11, 0xB)", Print('\v')); EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); EXPECT_EQ("' ' (32, 0x20)", Print(' ')); EXPECT_EQ("'a' (97, 0x61)", Print('a')); } // signed char. TEST(PrintCharTest, SignedChar) { EXPECT_EQ("'\\0'", Print(static_cast('\0'))); EXPECT_EQ("'\\xCE' (-50)", Print(static_cast(-50))); } // unsigned char. TEST(PrintCharTest, UnsignedChar) { EXPECT_EQ("'\\0'", Print(static_cast('\0'))); EXPECT_EQ("'b' (98, 0x62)", Print(static_cast('b'))); } // Tests printing other simple, built-in types. // bool. TEST(PrintBuiltInTypeTest, Bool) { EXPECT_EQ("false", Print(false)); EXPECT_EQ("true", Print(true)); } // wchar_t. TEST(PrintBuiltInTypeTest, Wchar_t) { EXPECT_EQ("L'\\0'", Print(L'\0')); EXPECT_EQ("L'\\'' (39, 0x27)", Print(L'\'')); EXPECT_EQ("L'\"' (34, 0x22)", Print(L'"')); EXPECT_EQ("L'?' (63, 0x3F)", Print(L'?')); EXPECT_EQ("L'\\\\' (92, 0x5C)", Print(L'\\')); EXPECT_EQ("L'\\a' (7)", Print(L'\a')); EXPECT_EQ("L'\\b' (8)", Print(L'\b')); EXPECT_EQ("L'\\f' (12, 0xC)", Print(L'\f')); EXPECT_EQ("L'\\n' (10, 0xA)", Print(L'\n')); EXPECT_EQ("L'\\r' (13, 0xD)", Print(L'\r')); EXPECT_EQ("L'\\t' (9)", Print(L'\t')); EXPECT_EQ("L'\\v' (11, 0xB)", Print(L'\v')); EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); EXPECT_EQ("L' ' (32, 0x20)", Print(L' ')); EXPECT_EQ("L'a' (97, 0x61)", Print(L'a')); EXPECT_EQ("L'\\x576' (1398)", Print(static_cast(0x576))); EXPECT_EQ("L'\\xC74D' (51021)", Print(static_cast(0xC74D))); } // Test that Int64 provides more storage than wchar_t. TEST(PrintTypeSizeTest, Wchar_t) { EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); } // Various integer types. TEST(PrintBuiltInTypeTest, Integer) { EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 EXPECT_EQ("18446744073709551615", Print(static_cast(-1))); // uint64 EXPECT_EQ("-9223372036854775808", Print(static_cast(1) << 63)); // int64 } // Size types. TEST(PrintBuiltInTypeTest, Size_t) { EXPECT_EQ("1", Print(sizeof('a'))); // size_t. #if !GTEST_OS_WINDOWS // Windows has no ssize_t type. EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. #endif // !GTEST_OS_WINDOWS } // Floating-points. TEST(PrintBuiltInTypeTest, FloatingPoints) { EXPECT_EQ("1.5", Print(1.5f)); // float EXPECT_EQ("-2.5", Print(-2.5)); // double } // Since ::std::stringstream::operator<<(const void *) formats the pointer // output differently with different compilers, we have to create the expected // output first and use it as our expectation. static string PrintPointer(const void *p) { ::std::stringstream expected_result_stream; expected_result_stream << p; return expected_result_stream.str(); } // Tests printing C strings. // const char*. TEST(PrintCStringTest, Const) { const char* p = "World"; EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); } // char*. TEST(PrintCStringTest, NonConst) { char p[] = "Hi"; EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", Print(static_cast(p))); } // NULL C string. TEST(PrintCStringTest, Null) { const char* p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests that C strings are escaped properly. TEST(PrintCStringTest, EscapesProperly) { const char* p = "'\"?\\\a\b\f\n\r\t\v\x7F\xFF a"; EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"?\\\\\\a\\b\\f" "\\n\\r\\t\\v\\x7F\\xFF a\"", Print(p)); } // 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) // const wchar_t*. TEST(PrintWideCStringTest, Const) { const wchar_t* p = L"World"; EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); } // wchar_t*. TEST(PrintWideCStringTest, NonConst) { wchar_t p[] = L"Hi"; EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", Print(static_cast(p))); } // NULL wide C string. TEST(PrintWideCStringTest, Null) { const wchar_t* p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests that wide C strings are escaped properly. TEST(PrintWideCStringTest, EscapesProperly) { const wchar_t s[] = {'\'', '"', '?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', 0xD3, 0x576, 0x8D3, 0xC74D, ' ', 'a', '\0'}; EXPECT_EQ(PrintPointer(s) + " pointing to L\"'\\\"?\\\\\\a\\b\\f" "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", Print(static_cast(s))); } #endif // native wchar_t // Tests printing pointers to other char types. // signed char*. TEST(PrintCharPointerTest, SignedChar) { signed char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const signed char*. TEST(PrintCharPointerTest, ConstSignedChar) { signed char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // unsigned char*. TEST(PrintCharPointerTest, UnsignedChar) { unsigned char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const unsigned char*. TEST(PrintCharPointerTest, ConstUnsignedChar) { const unsigned char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing pointers to simple, built-in types. // bool*. TEST(PrintPointerToBuiltInTypeTest, Bool) { bool* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // void*. TEST(PrintPointerToBuiltInTypeTest, Void) { void* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const void*. TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { const void* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing pointers to pointers. TEST(PrintPointerToPointerTest, IntPointerPointer) { int** p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing (non-member) function pointers. void MyFunction(int /* n */) {} TEST(PrintPointerTest, NonMemberFunctionPointer) { // We cannot directly cast &MyFunction to const void* because the // standard disallows casting between pointers to functions and // pointers to objects, and some compilers (e.g. GCC 3.4) enforce // this limitation. EXPECT_EQ( PrintPointer(reinterpret_cast( reinterpret_cast(&MyFunction))), Print(&MyFunction)); int (*p)(bool) = NULL; // NOLINT EXPECT_EQ("NULL", Print(p)); } // An assertion predicate determining whether a one string is a prefix for // another. template AssertionResult HasPrefix(const StringType& str, const StringType& prefix) { if (str.find(prefix, 0) == 0) return AssertionSuccess(); const bool is_wide_string = sizeof(prefix[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << begin_string_quote << prefix << "\" is not a prefix of " << begin_string_quote << str << "\"\n"; } // Tests printing member variable pointers. Although they are called // pointers, they don't point to a location in the address space. // Their representation is implementation-defined. Thus they will be // printed as raw bytes. struct Foo { public: virtual ~Foo() {} int MyMethod(char x) { return x + 1; } virtual char MyVirtualMethod(int /* n */) { return 'a'; } int value; }; TEST(PrintPointerTest, MemberVariablePointer) { EXPECT_TRUE(HasPrefix(Print(&Foo::value), Print(sizeof(&Foo::value)) + "-byte object ")); int (Foo::*p) = NULL; // NOLINT EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object ")); } // Tests printing member function pointers. Although they are called // pointers, they don't point to a location in the address space. // Their representation is implementation-defined. Thus they will be // printed as raw bytes. TEST(PrintPointerTest, MemberFunctionPointer) { EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod), Print(sizeof(&Foo::MyMethod)) + "-byte object ")); EXPECT_TRUE( HasPrefix(Print(&Foo::MyVirtualMethod), Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object ")); int (Foo::*p)(char) = NULL; // NOLINT EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object ")); } // Tests printing C arrays. // The difference between this and Print() is that it ensures that the // argument is a reference to an array. template string PrintArrayHelper(T (&a)[N]) { return Print(a); } // One-dimensional array. TEST(PrintArrayTest, OneDimensionalArray) { int a[5] = { 1, 2, 3, 4, 5 }; EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); } // Two-dimensional array. TEST(PrintArrayTest, TwoDimensionalArray) { int a[2][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }; EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); } // Array of const elements. TEST(PrintArrayTest, ConstArray) { const bool a[1] = { false }; EXPECT_EQ("{ false }", PrintArrayHelper(a)); } // char array without terminating NUL. TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) { // Array a contains '\0' in the middle and doesn't end with '\0'. char a[] = { 'H', '\0', 'i' }; EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); } // const char array with terminating NUL. TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) { const char a[] = "\0Hi"; EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a)); } // const wchar_t array without terminating NUL. TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) { // Array a contains '\0' in the middle and doesn't end with '\0'. const wchar_t a[] = { L'H', L'\0', L'i' }; EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); } // wchar_t array with terminating NUL. TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) { const wchar_t a[] = L"\0Hi"; EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a)); } // Array of objects. TEST(PrintArrayTest, ObjectArray) { string a[3] = { "Hi", "Hello", "Ni hao" }; EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); } // Array with many elements. TEST(PrintArrayTest, BigArray) { int a[100] = { 1, 2, 3 }; EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", PrintArrayHelper(a)); } // Tests printing ::string and ::std::string. #if GTEST_HAS_GLOBAL_STRING // ::string. TEST(PrintStringTest, StringInGlobalNamespace) { const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; const ::string str(s, sizeof(s)); EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", Print(str)); } #endif // GTEST_HAS_GLOBAL_STRING // ::std::string. TEST(PrintStringTest, StringInStdNamespace) { const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; const ::std::string str(s, sizeof(s)); EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", Print(str)); } TEST(PrintStringTest, StringAmbiguousHex) { // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of: // '\x6', '\x6B', or '\x6BA'. // a hex escaping sequence following by a decimal digit EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3"))); // a hex escaping sequence following by a hex digit (lower-case) EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas"))); // a hex escaping sequence following by a hex digit (upper-case) EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA"))); // a hex escaping sequence following by a non-xdigit EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!"))); } // Tests printing ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING // ::wstring. TEST(PrintWideStringTest, StringInGlobalNamespace) { const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" "\\xD3\\x576\\x8D3\\xC74D a\\0\"", Print(str)); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING // ::std::wstring. TEST(PrintWideStringTest, StringInStdNamespace) { const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" "\\xD3\\x576\\x8D3\\xC74D a\\0\"", Print(str)); } TEST(PrintWideStringTest, StringAmbiguousHex) { // same for wide strings. EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3"))); EXPECT_EQ("L\"mm\\x6\" L\"bananas\"", Print(::std::wstring(L"mm\x6" L"bananas"))); EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"", Print(::std::wstring(L"NOM\x6" L"BANANA"))); EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!"))); } #endif // GTEST_HAS_STD_WSTRING // Tests printing types that support generic streaming (i.e. streaming // to std::basic_ostream for any valid Char and // CharTraits types). // Tests printing a non-template type that supports generic streaming. class AllowsGenericStreaming {}; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreaming& /* a */) { return os << "AllowsGenericStreaming"; } TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { AllowsGenericStreaming a; EXPECT_EQ("AllowsGenericStreaming", Print(a)); } // Tests printing a template type that supports generic streaming. template class AllowsGenericStreamingTemplate {}; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreamingTemplate& /* a */) { return os << "AllowsGenericStreamingTemplate"; } TEST(PrintTypeWithGenericStreamingTest, TemplateType) { AllowsGenericStreamingTemplate a; EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); } // Tests printing a type that supports generic streaming and can be // implicitly converted to another printable type. template class AllowsGenericStreamingAndImplicitConversionTemplate { public: operator bool() const { return false; } }; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; } TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { AllowsGenericStreamingAndImplicitConversionTemplate a; EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); } #if GTEST_HAS_STRING_PIECE_ // Tests printing StringPiece. TEST(PrintStringPieceTest, SimpleStringPiece) { const StringPiece sp = "Hello"; EXPECT_EQ("\"Hello\"", Print(sp)); } TEST(PrintStringPieceTest, UnprintableCharacters) { const char str[] = "NUL (\0) and \r\t"; const StringPiece sp(str, sizeof(str) - 1); EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp)); } #endif // GTEST_HAS_STRING_PIECE_ // Tests printing STL containers. TEST(PrintStlContainerTest, EmptyDeque) { deque empty; EXPECT_EQ("{}", Print(empty)); } TEST(PrintStlContainerTest, NonEmptyDeque) { deque non_empty; non_empty.push_back(1); non_empty.push_back(3); EXPECT_EQ("{ 1, 3 }", Print(non_empty)); } #if GTEST_HAS_HASH_MAP_ TEST(PrintStlContainerTest, OneElementHashMap) { hash_map map1; map1[1] = 'a'; EXPECT_EQ("{ (1, 'a' (97, 0x61)) }", Print(map1)); } TEST(PrintStlContainerTest, HashMultiMap) { hash_multimap map1; map1.insert(make_pair(5, true)); map1.insert(make_pair(5, false)); // Elements of hash_multimap can be printed in any order. const string result = Print(map1); EXPECT_TRUE(result == "{ (5, true), (5, false) }" || result == "{ (5, false), (5, true) }") << " where Print(map1) returns \"" << result << "\"."; } #endif // GTEST_HAS_HASH_MAP_ #if GTEST_HAS_HASH_SET_ TEST(PrintStlContainerTest, HashSet) { hash_set set1; set1.insert("hello"); EXPECT_EQ("{ \"hello\" }", Print(set1)); } TEST(PrintStlContainerTest, HashMultiSet) { const int kSize = 5; int a[kSize] = { 1, 1, 2, 5, 1 }; hash_multiset set1(a, a + kSize); // Elements of hash_multiset can be printed in any order. const string result = Print(set1); const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. // Verifies the result matches the expected pattern; also extracts // the numbers in the result. ASSERT_EQ(expected_pattern.length(), result.length()); std::vector numbers; for (size_t i = 0; i != result.length(); i++) { if (expected_pattern[i] == 'd') { ASSERT_NE(isdigit(static_cast(result[i])), 0); numbers.push_back(result[i] - '0'); } else { EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " << result; } } // Makes sure the result contains the right numbers. std::sort(numbers.begin(), numbers.end()); std::sort(a, a + kSize); EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); } #endif // GTEST_HAS_HASH_SET_ TEST(PrintStlContainerTest, List) { const string a[] = { "hello", "world" }; const list strings(a, a + 2); EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); } TEST(PrintStlContainerTest, Map) { map map1; map1[1] = true; map1[5] = false; map1[3] = true; EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); } TEST(PrintStlContainerTest, MultiMap) { multimap map1; // The make_pair template function would deduce the type as // pair here, and since the key part in a multimap has to // be constant, without a templated ctor in the pair class (as in // libCstd on Solaris), make_pair call would fail to compile as no // implicit conversion is found. Thus explicit typename is used // here instead. map1.insert(pair(true, 0)); map1.insert(pair(true, 1)); map1.insert(pair(false, 2)); EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); } TEST(PrintStlContainerTest, Set) { const unsigned int a[] = { 3, 0, 5 }; set set1(a, a + 3); EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); } TEST(PrintStlContainerTest, MultiSet) { const int a[] = { 1, 1, 2, 5, 1 }; multiset set1(a, a + 5); EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); } TEST(PrintStlContainerTest, Pair) { pair p(true, 5); EXPECT_EQ("(true, 5)", Print(p)); } TEST(PrintStlContainerTest, Vector) { vector v; v.push_back(1); v.push_back(2); EXPECT_EQ("{ 1, 2 }", Print(v)); } TEST(PrintStlContainerTest, LongSequence) { const int a[100] = { 1, 2, 3 }; const vector v(a, a + 100); EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); } TEST(PrintStlContainerTest, NestedContainer) { const int a1[] = { 1, 2 }; const int a2[] = { 3, 4, 5 }; const list l1(a1, a1 + 2); const list l2(a2, a2 + 3); vector > v; v.push_back(l1); v.push_back(l2); EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); } TEST(PrintStlContainerTest, OneDimensionalNativeArray) { const int a[3] = { 1, 2, 3 }; NativeArray b(a, 3, kReference); EXPECT_EQ("{ 1, 2, 3 }", Print(b)); } TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; NativeArray b(a, 2, kReference); EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); } // Tests that a class named iterator isn't treated as a container. struct iterator { char x; }; TEST(PrintStlContainerTest, Iterator) { iterator it = {}; EXPECT_EQ("1-byte object <00>", Print(it)); } // Tests that a class named const_iterator isn't treated as a container. struct const_iterator { char x; }; TEST(PrintStlContainerTest, ConstIterator) { const_iterator it = {}; EXPECT_EQ("1-byte object <00>", Print(it)); } #if GTEST_HAS_TR1_TUPLE // Tests printing tuples. // Tuples of various arities. TEST(PrintTupleTest, VariousSizes) { tuple<> t0; EXPECT_EQ("()", Print(t0)); tuple t1(5); EXPECT_EQ("(5)", Print(t1)); tuple t2('a', true); EXPECT_EQ("('a' (97, 0x61), true)", Print(t2)); tuple t3(false, 2, 3); EXPECT_EQ("(false, 2, 3)", Print(t3)); tuple t4(false, 2, 3, 4); EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); tuple t5(false, 2, 3, 4, true); EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); tuple t6(false, 2, 3, 4, true, 6); EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); tuple t7(false, 2, 3, 4, true, 6, 7); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); tuple t8( false, 2, 3, 4, true, 6, 7, true); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); tuple t9( false, 2, 3, 4, true, 6, 7, true, 9); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); const char* const str = "8"; // VC++ 2010's implementation of tuple of C++0x is deficient, requiring // an explicit type cast of NULL to be used. tuple t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, ImplicitCast_(NULL), "10"); EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + " pointing to \"8\", NULL, \"10\")", Print(t10)); } // Nested tuples. TEST(PrintTupleTest, NestedTuple) { tuple, char> nested(make_tuple(5, true), 'a'); EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested)); } #endif // GTEST_HAS_TR1_TUPLE // Tests printing user-defined unprintable types. // Unprintable types in the global namespace. TEST(PrintUnprintableTypeTest, InGlobalNamespace) { EXPECT_EQ("1-byte object <00>", Print(UnprintableTemplateInGlobal())); } // Unprintable types in a user namespace. TEST(PrintUnprintableTypeTest, InUserNamespace) { EXPECT_EQ("16-byte object ", Print(::foo::UnprintableInFoo())); } // Unprintable types are that too big to be printed completely. struct Big { Big() { memset(array, 0, sizeof(array)); } char array[257]; }; TEST(PrintUnpritableTypeTest, BigObject) { EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>", Print(Big())); } // Tests printing user-defined streamable types. // Streamable types in the global namespace. TEST(PrintStreamableTypeTest, InGlobalNamespace) { StreamableInGlobal x; EXPECT_EQ("StreamableInGlobal", Print(x)); EXPECT_EQ("StreamableInGlobal*", Print(&x)); } // Printable template types in a user namespace. TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { EXPECT_EQ("StreamableTemplateInFoo: 0", Print(::foo::StreamableTemplateInFoo())); } // Tests printing user-defined types that have a PrintTo() function. TEST(PrintPrintableTypeTest, InUserNamespace) { EXPECT_EQ("PrintableViaPrintTo: 0", Print(::foo::PrintableViaPrintTo())); } // Tests printing a pointer to a user-defined type that has a << // operator for its pointer. TEST(PrintPrintableTypeTest, PointerInUserNamespace) { ::foo::PointerPrintable x; EXPECT_EQ("PointerPrintable*", Print(&x)); } // Tests printing user-defined class template that have a PrintTo() function. TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { EXPECT_EQ("PrintableViaPrintToTemplate: 5", Print(::foo::PrintableViaPrintToTemplate(5))); } #if GTEST_HAS_PROTOBUF_ // Tests printing a protocol message. TEST(PrintProtocolMessageTest, PrintsShortDebugString) { testing::internal::TestMessage msg; msg.set_member("yes"); EXPECT_EQ("", Print(msg)); } // Tests printing a short proto2 message. TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { testing::internal::FooMessage msg; msg.set_int_field(2); msg.set_string_field("hello"); EXPECT_PRED2(RE::FullMatch, Print(msg), ""); } // Tests printing a long proto2 message. TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) { testing::internal::FooMessage msg; msg.set_int_field(2); msg.set_string_field("hello"); msg.add_names("peter"); msg.add_names("paul"); msg.add_names("mary"); EXPECT_PRED2(RE::FullMatch, Print(msg), "<\n" "int_field:\\s*2\n" "string_field:\\s*\"hello\"\n" "names:\\s*\"peter\"\n" "names:\\s*\"paul\"\n" "names:\\s*\"mary\"\n" ">"); } #endif // GTEST_HAS_PROTOBUF_ // Tests that the universal printer prints both the address and the // value of a reference. TEST(PrintReferenceTest, PrintsAddressAndValue) { int n = 5; EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", PrintByRef(a)); const ::foo::UnprintableInFoo x; EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " "", PrintByRef(x)); } // Tests that the universal printer prints a function pointer passed by // reference. TEST(PrintReferenceTest, HandlesFunctionPointer) { void (*fp)(int n) = &MyFunction; const string fp_pointer_string = PrintPointer(reinterpret_cast(&fp)); // We cannot directly cast &MyFunction to const void* because the // standard disallows casting between pointers to functions and // pointers to objects, and some compilers (e.g. GCC 3.4) enforce // this limitation. const string fp_string = PrintPointer(reinterpret_cast( reinterpret_cast(fp))); EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, PrintByRef(fp)); } // Tests that the universal printer prints a member function pointer // passed by reference. TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { int (Foo::*p)(char ch) = &Foo::MyMethod; EXPECT_TRUE(HasPrefix( PrintByRef(p), "@" + PrintPointer(reinterpret_cast(&p)) + " " + Print(sizeof(p)) + "-byte object ")); char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; EXPECT_TRUE(HasPrefix( PrintByRef(p2), "@" + PrintPointer(reinterpret_cast(&p2)) + " " + Print(sizeof(p2)) + "-byte object ")); } // Tests that the universal printer prints a member variable pointer // passed by reference. TEST(PrintReferenceTest, HandlesMemberVariablePointer) { int (Foo::*p) = &Foo::value; // NOLINT EXPECT_TRUE(HasPrefix( PrintByRef(p), "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); } // Tests that FormatForComparisonFailureMessage(), which is used to print // an operand in a comparison assertion (e.g. ASSERT_EQ) when the assertion // fails, formats the operand in the desired way. // scalar TEST(FormatForComparisonFailureMessageTest, WorksForScalar) { EXPECT_STREQ("123", FormatForComparisonFailureMessage(123, 124).c_str()); } // non-char pointer TEST(FormatForComparisonFailureMessageTest, WorksForNonCharPointer) { int n = 0; EXPECT_EQ(PrintPointer(&n), FormatForComparisonFailureMessage(&n, &n).c_str()); } // non-char array TEST(FormatForComparisonFailureMessageTest, FormatsNonCharArrayAsPointer) { // In expression 'array == x', 'array' is compared by pointer. // Therefore we want to print an array operand as a pointer. int n[] = { 1, 2, 3 }; EXPECT_EQ(PrintPointer(n), FormatForComparisonFailureMessage(n, n).c_str()); } // Tests formatting a char pointer when it's compared with another pointer. // In this case we want to print it as a raw pointer, as the comparision is by // pointer. // char pointer vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsPointer) { // In expression 'p == x', where 'p' and 'x' are (const or not) char // pointers, the operands are compared by pointer. Therefore we // want to print 'p' as a pointer instead of a C string (we don't // even know if it's supposed to point to a valid C string). // const char* const char* s = "hello"; EXPECT_EQ(PrintPointer(s), FormatForComparisonFailureMessage(s, s).c_str()); // char* char ch = 'a'; EXPECT_EQ(PrintPointer(&ch), FormatForComparisonFailureMessage(&ch, &ch).c_str()); } // wchar_t pointer vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsPointer) { // In expression 'p == x', where 'p' and 'x' are (const or not) char // pointers, the operands are compared by pointer. Therefore we // want to print 'p' as a pointer instead of a wide C string (we don't // even know if it's supposed to point to a valid wide C string). // const wchar_t* const wchar_t* s = L"hello"; EXPECT_EQ(PrintPointer(s), FormatForComparisonFailureMessage(s, s).c_str()); // wchar_t* wchar_t ch = L'a'; EXPECT_EQ(PrintPointer(&ch), FormatForComparisonFailureMessage(&ch, &ch).c_str()); } // Tests formatting a char pointer when it's compared to a string object. // In this case we want to print the char pointer as a C string. #if GTEST_HAS_GLOBAL_STRING // char pointer vs ::string TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsString) { const char* s = "hello \"world"; EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::string()).c_str()); // char* char str[] = "hi\1"; char* p = str; EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::string()).c_str()); } #endif // char pointer vs std::string TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsStdString) { const char* s = "hello \"world"; EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::std::string()).c_str()); // char* char str[] = "hi\1"; char* p = str; EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::std::string()).c_str()); } #if GTEST_HAS_GLOBAL_WSTRING // wchar_t pointer vs ::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsWString) { const wchar_t* s = L"hi \"world"; EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::wstring()).c_str()); // wchar_t* wchar_t str[] = L"hi\1"; wchar_t* p = str; EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::wstring()).c_str()); } #endif #if GTEST_HAS_STD_WSTRING // wchar_t pointer vs std::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsStdWString) { const wchar_t* s = L"hi \"world"; EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::std::wstring()).c_str()); // wchar_t* wchar_t str[] = L"hi\1"; wchar_t* p = str; EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::std::wstring()).c_str()); } #endif // Tests formatting a char array when it's compared with a pointer or array. // In this case we want to print the array as a row pointer, as the comparison // is by pointer. // char array vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsPointer) { char str[] = "hi \"world\""; char* p = NULL; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, p).c_str()); } // char array vs char array TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsCharArray) { const char str[] = "hi \"world\""; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, str).c_str()); } // wchar_t array vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsPointer) { wchar_t str[] = L"hi \"world\""; wchar_t* p = NULL; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, p).c_str()); } // wchar_t array vs wchar_t array TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWCharArray) { const wchar_t str[] = L"hi \"world\""; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, str).c_str()); } // Tests formatting a char array when it's compared with a string object. // In this case we want to print the array as a C string. #if GTEST_HAS_GLOBAL_STRING // char array vs string TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsString) { const char str[] = "hi \"w\0rld\""; EXPECT_STREQ("\"hi \\\"w\"", // The content should be escaped. // Embedded NUL terminates the string. FormatForComparisonFailureMessage(str, ::string()).c_str()); } #endif // char array vs std::string TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsStdString) { const char str[] = "hi \"world\""; EXPECT_STREQ("\"hi \\\"world\\\"\"", // The content should be escaped. FormatForComparisonFailureMessage(str, ::std::string()).c_str()); } #if GTEST_HAS_GLOBAL_WSTRING // wchar_t array vs wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWString) { const wchar_t str[] = L"hi \"world\""; EXPECT_STREQ("L\"hi \\\"world\\\"\"", // The content should be escaped. FormatForComparisonFailureMessage(str, ::wstring()).c_str()); } #endif #if GTEST_HAS_STD_WSTRING // wchar_t array vs std::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsStdWString) { const wchar_t str[] = L"hi \"w\0rld\""; EXPECT_STREQ( "L\"hi \\\"w\"", // The content should be escaped. // Embedded NUL terminates the string. FormatForComparisonFailureMessage(str, ::std::wstring()).c_str()); } #endif // Useful for testing PrintToString(). We cannot use EXPECT_EQ() // there as its implementation uses PrintToString(). The caller must // ensure that 'value' has no side effect. #define EXPECT_PRINT_TO_STRING_(value, expected_string) \ EXPECT_TRUE(PrintToString(value) == (expected_string)) \ << " where " #value " prints as " << (PrintToString(value)) TEST(PrintToStringTest, WorksForScalar) { EXPECT_PRINT_TO_STRING_(123, "123"); } TEST(PrintToStringTest, WorksForPointerToConstChar) { const char* p = "hello"; EXPECT_PRINT_TO_STRING_(p, "\"hello\""); } TEST(PrintToStringTest, WorksForPointerToNonConstChar) { char s[] = "hello"; char* p = s; EXPECT_PRINT_TO_STRING_(p, "\"hello\""); } TEST(PrintToStringTest, EscapesForPointerToConstChar) { const char* p = "hello\n"; EXPECT_PRINT_TO_STRING_(p, "\"hello\\n\""); } TEST(PrintToStringTest, EscapesForPointerToNonConstChar) { char s[] = "hello\1"; char* p = s; EXPECT_PRINT_TO_STRING_(p, "\"hello\\x1\""); } TEST(PrintToStringTest, WorksForArray) { int n[3] = { 1, 2, 3 }; EXPECT_PRINT_TO_STRING_(n, "{ 1, 2, 3 }"); } TEST(PrintToStringTest, WorksForCharArray) { char s[] = "hello"; EXPECT_PRINT_TO_STRING_(s, "\"hello\""); } TEST(PrintToStringTest, WorksForCharArrayWithEmbeddedNul) { const char str_with_nul[] = "hello\0 world"; EXPECT_PRINT_TO_STRING_(str_with_nul, "\"hello\\0 world\""); char mutable_str_with_nul[] = "hello\0 world"; EXPECT_PRINT_TO_STRING_(mutable_str_with_nul, "\"hello\\0 world\""); } #undef EXPECT_PRINT_TO_STRING_ TEST(UniversalTersePrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalTersePrint(123, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalTersePrintTest, WorksForReference) { const int& n = 123; ::std::stringstream ss; UniversalTersePrint(n, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalTersePrintTest, WorksForCString) { const char* s1 = "abc"; ::std::stringstream ss1; UniversalTersePrint(s1, &ss1); EXPECT_EQ("\"abc\"", ss1.str()); char* s2 = const_cast(s1); ::std::stringstream ss2; UniversalTersePrint(s2, &ss2); EXPECT_EQ("\"abc\"", ss2.str()); const char* s3 = NULL; ::std::stringstream ss3; UniversalTersePrint(s3, &ss3); EXPECT_EQ("NULL", ss3.str()); } TEST(UniversalPrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalPrint(123, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalPrintTest, WorksForReference) { const int& n = 123; ::std::stringstream ss; UniversalPrint(n, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalPrintTest, WorksForCString) { const char* s1 = "abc"; ::std::stringstream ss1; UniversalPrint(s1, &ss1); EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); char* s2 = const_cast(s1); ::std::stringstream ss2; UniversalPrint(s2, &ss2); EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); const char* s3 = NULL; ::std::stringstream ss3; UniversalPrint(s3, &ss3); EXPECT_EQ("NULL", ss3.str()); } TEST(UniversalPrintTest, WorksForCharArray) { const char str[] = "\"Line\0 1\"\nLine 2"; ::std::stringstream ss1; UniversalPrint(str, &ss1); EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss1.str()); const char mutable_str[] = "\"Line\0 1\"\nLine 2"; ::std::stringstream ss2; UniversalPrint(mutable_str, &ss2); EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss2.str()); } #if GTEST_HAS_TR1_TUPLE TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple()); EXPECT_EQ(0u, result.size()); } TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1)); ASSERT_EQ(1u, result.size()); EXPECT_EQ("1", result[0]); } TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("'a' (97, 0x61)", result[1]); } TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) { const int n = 1; Strings result = UniversalTersePrintTupleFieldsToStrings( tuple(n, "a")); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("\"a\"", result[1]); } #endif // GTEST_HAS_TR1_TUPLE } // namespace gtest_printers_test } // namespace testing mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-test-part_test.cc000066400000000000000000000161621273231111400304710ustar00rootroot00000000000000// 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) // #include "gtest/gtest-test-part.h" #include "gtest/gtest.h" using testing::Message; using testing::Test; using testing::TestPartResult; using testing::TestPartResultArray; namespace { // Tests the TestPartResult class. // The test fixture for testing TestPartResult. class TestPartResultTest : public Test { protected: TestPartResultTest() : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"), r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"), r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {} TestPartResult r1_, r2_, r3_; }; TEST_F(TestPartResultTest, ConstructorWorks) { Message message; message << "something is terribly wrong"; message << static_cast(testing::internal::kStackTraceMarker); message << "some unimportant stack trace"; const TestPartResult result(TestPartResult::kNonFatalFailure, "some_file.cc", 42, message.GetString().c_str()); EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type()); EXPECT_STREQ("some_file.cc", result.file_name()); EXPECT_EQ(42, result.line_number()); EXPECT_STREQ(message.GetString().c_str(), result.message()); EXPECT_STREQ("something is terribly wrong", result.summary()); } TEST_F(TestPartResultTest, ResultAccessorsWork) { const TestPartResult success(TestPartResult::kSuccess, "file.cc", 42, "message"); EXPECT_TRUE(success.passed()); EXPECT_FALSE(success.failed()); EXPECT_FALSE(success.nonfatally_failed()); EXPECT_FALSE(success.fatally_failed()); const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure, "file.cc", 42, "message"); EXPECT_FALSE(nonfatal_failure.passed()); EXPECT_TRUE(nonfatal_failure.failed()); EXPECT_TRUE(nonfatal_failure.nonfatally_failed()); EXPECT_FALSE(nonfatal_failure.fatally_failed()); const TestPartResult fatal_failure(TestPartResult::kFatalFailure, "file.cc", 42, "message"); EXPECT_FALSE(fatal_failure.passed()); EXPECT_TRUE(fatal_failure.failed()); EXPECT_FALSE(fatal_failure.nonfatally_failed()); EXPECT_TRUE(fatal_failure.fatally_failed()); } // Tests TestPartResult::type(). TEST_F(TestPartResultTest, type) { EXPECT_EQ(TestPartResult::kSuccess, r1_.type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type()); EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type()); } // Tests TestPartResult::file_name(). TEST_F(TestPartResultTest, file_name) { EXPECT_STREQ("foo/bar.cc", r1_.file_name()); EXPECT_STREQ(NULL, r3_.file_name()); } // Tests TestPartResult::line_number(). TEST_F(TestPartResultTest, line_number) { EXPECT_EQ(10, r1_.line_number()); EXPECT_EQ(-1, r2_.line_number()); } // Tests TestPartResult::message(). TEST_F(TestPartResultTest, message) { EXPECT_STREQ("Success!", r1_.message()); } // Tests TestPartResult::passed(). TEST_F(TestPartResultTest, Passed) { EXPECT_TRUE(r1_.passed()); EXPECT_FALSE(r2_.passed()); EXPECT_FALSE(r3_.passed()); } // Tests TestPartResult::failed(). TEST_F(TestPartResultTest, Failed) { EXPECT_FALSE(r1_.failed()); EXPECT_TRUE(r2_.failed()); EXPECT_TRUE(r3_.failed()); } // Tests TestPartResult::fatally_failed(). TEST_F(TestPartResultTest, FatallyFailed) { EXPECT_FALSE(r1_.fatally_failed()); EXPECT_FALSE(r2_.fatally_failed()); EXPECT_TRUE(r3_.fatally_failed()); } // Tests TestPartResult::nonfatally_failed(). TEST_F(TestPartResultTest, NonfatallyFailed) { EXPECT_FALSE(r1_.nonfatally_failed()); EXPECT_TRUE(r2_.nonfatally_failed()); EXPECT_FALSE(r3_.nonfatally_failed()); } // Tests the TestPartResultArray class. class TestPartResultArrayTest : public Test { protected: TestPartResultArrayTest() : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"), r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {} const TestPartResult r1_, r2_; }; // Tests that TestPartResultArray initially has size 0. TEST_F(TestPartResultArrayTest, InitialSizeIsZero) { TestPartResultArray results; EXPECT_EQ(0, results.size()); } // Tests that TestPartResultArray contains the given TestPartResult // after one Append() operation. TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend) { TestPartResultArray results; results.Append(r1_); EXPECT_EQ(1, results.size()); EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); } // Tests that TestPartResultArray contains the given TestPartResults // after two Append() operations. TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) { TestPartResultArray results; results.Append(r1_); results.Append(r2_); EXPECT_EQ(2, results.size()); EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message()); } typedef TestPartResultArrayTest TestPartResultArrayDeathTest; // Tests that the program dies when GetTestPartResult() is called with // an invalid index. TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) { TestPartResultArray results; results.Append(r1_); EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), ""); EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), ""); } // TODO(mheule@google.com): Add a test for the class HasNewFatalFailureHelper. } // namespace mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-tuple_test.cc000066400000000000000000000220421273231111400276710ustar00rootroot00000000000000// 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) #include "gtest/internal/gtest-tuple.h" #include #include "gtest/gtest.h" namespace { using ::std::tr1::get; using ::std::tr1::make_tuple; using ::std::tr1::tuple; using ::std::tr1::tuple_element; using ::std::tr1::tuple_size; using ::testing::StaticAssertTypeEq; // Tests that tuple_element >::type returns TK. TEST(tuple_element_Test, ReturnsElementType) { StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); } // Tests that tuple_size::value gives the number of fields in tuple // type T. TEST(tuple_size_Test, ReturnsNumberOfFields) { EXPECT_EQ(0, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +(tuple_size > >::value)); EXPECT_EQ(2, +(tuple_size >::value)); EXPECT_EQ(3, +(tuple_size >::value)); } // Tests comparing a tuple with itself. TEST(ComparisonTest, ComparesWithSelf) { const tuple a(5, 'a', false); EXPECT_TRUE(a == a); EXPECT_FALSE(a != a); } // Tests comparing two tuples with the same value. TEST(ComparisonTest, ComparesEqualTuples) { const tuple a(5, true), b(5, true); EXPECT_TRUE(a == b); EXPECT_FALSE(a != b); } // Tests comparing two different tuples that have no reference fields. TEST(ComparisonTest, ComparesUnequalTuplesWithoutReferenceFields) { typedef tuple FooTuple; const FooTuple a(0, 'x'); const FooTuple b(1, 'a'); EXPECT_TRUE(a != b); EXPECT_FALSE(a == b); const FooTuple c(1, 'b'); EXPECT_TRUE(b != c); EXPECT_FALSE(b == c); } // Tests comparing two different tuples that have reference fields. TEST(ComparisonTest, ComparesUnequalTuplesWithReferenceFields) { typedef tuple FooTuple; int i = 5; const char ch = 'a'; const FooTuple a(i, ch); int j = 6; const FooTuple b(j, ch); EXPECT_TRUE(a != b); EXPECT_FALSE(a == b); j = 5; const char ch2 = 'b'; const FooTuple c(j, ch2); EXPECT_TRUE(b != c); EXPECT_FALSE(b == c); } // Tests that a tuple field with a reference type is an alias of the // variable it's supposed to reference. TEST(ReferenceFieldTest, IsAliasOfReferencedVariable) { int n = 0; tuple t(true, n); n = 1; EXPECT_EQ(n, get<1>(t)) << "Changing a underlying variable should update the reference field."; // Makes sure that the implementation doesn't do anything funny with // the & operator for the return type of get<>(). EXPECT_EQ(&n, &(get<1>(t))) << "The address of a reference field should equal the address of " << "the underlying variable."; get<1>(t) = 2; EXPECT_EQ(2, n) << "Changing a reference field should update the underlying variable."; } // Tests that tuple's default constructor default initializes each field. // This test needs to compile without generating warnings. TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField) { // The TR1 report requires that tuple's default constructor default // initializes each field, even if it's a primitive type. If the // implementation forgets to do this, this test will catch it by // generating warnings about using uninitialized variables (assuming // a decent compiler). tuple<> empty; tuple a1, b1; b1 = a1; EXPECT_EQ(0, get<0>(b1)); tuple a2, b2; b2 = a2; EXPECT_EQ(0, get<0>(b2)); EXPECT_EQ(0.0, get<1>(b2)); tuple a3, b3; b3 = a3; EXPECT_EQ(0.0, get<0>(b3)); EXPECT_EQ('\0', get<1>(b3)); EXPECT_TRUE(get<2>(b3) == NULL); tuple a10, b10; b10 = a10; EXPECT_EQ(0, get<0>(b10)); EXPECT_EQ(0, get<1>(b10)); EXPECT_EQ(0, get<2>(b10)); EXPECT_EQ(0, get<3>(b10)); EXPECT_EQ(0, get<4>(b10)); EXPECT_EQ(0, get<5>(b10)); EXPECT_EQ(0, get<6>(b10)); EXPECT_EQ(0, get<7>(b10)); EXPECT_EQ(0, get<8>(b10)); EXPECT_EQ(0, get<9>(b10)); } // Tests constructing a tuple from its fields. TEST(TupleConstructorTest, ConstructsFromFields) { int n = 1; // Reference field. tuple a(n); EXPECT_EQ(&n, &(get<0>(a))); // Non-reference fields. tuple b(5, 'a'); EXPECT_EQ(5, get<0>(b)); EXPECT_EQ('a', get<1>(b)); // Const reference field. const int m = 2; tuple c(true, m); EXPECT_TRUE(get<0>(c)); EXPECT_EQ(&m, &(get<1>(c))); } // Tests tuple's copy constructor. TEST(TupleConstructorTest, CopyConstructor) { tuple a(0.0, true); tuple b(a); EXPECT_DOUBLE_EQ(0.0, get<0>(b)); EXPECT_TRUE(get<1>(b)); } // Tests constructing a tuple from another tuple that has a compatible // but different type. TEST(TupleConstructorTest, ConstructsFromDifferentTupleType) { tuple a(0, 1, 'a'); tuple b(a); EXPECT_DOUBLE_EQ(0.0, get<0>(b)); EXPECT_EQ(1, get<1>(b)); EXPECT_EQ('a', get<2>(b)); } // Tests constructing a 2-tuple from an std::pair. TEST(TupleConstructorTest, ConstructsFromPair) { ::std::pair a(1, 'a'); tuple b(a); tuple c(a); } // Tests assigning a tuple to another tuple with the same type. TEST(TupleAssignmentTest, AssignsToSameTupleType) { const tuple a(5, 7L); tuple b; b = a; EXPECT_EQ(5, get<0>(b)); EXPECT_EQ(7L, get<1>(b)); } // Tests assigning a tuple to another tuple with a different but // compatible type. TEST(TupleAssignmentTest, AssignsToDifferentTupleType) { const tuple a(1, 7L, true); tuple b; b = a; EXPECT_EQ(1L, get<0>(b)); EXPECT_EQ(7, get<1>(b)); EXPECT_TRUE(get<2>(b)); } // Tests assigning an std::pair to a 2-tuple. TEST(TupleAssignmentTest, AssignsFromPair) { const ::std::pair a(5, true); tuple b; b = a; EXPECT_EQ(5, get<0>(b)); EXPECT_TRUE(get<1>(b)); tuple c; c = a; EXPECT_EQ(5L, get<0>(c)); EXPECT_TRUE(get<1>(c)); } // A fixture for testing big tuples. class BigTupleTest : public testing::Test { protected: typedef tuple BigTuple; BigTupleTest() : a_(1, 0, 0, 0, 0, 0, 0, 0, 0, 2), b_(1, 0, 0, 0, 0, 0, 0, 0, 0, 3) {} BigTuple a_, b_; }; // Tests constructing big tuples. TEST_F(BigTupleTest, Construction) { BigTuple a; BigTuple b(b_); } // Tests that get(t) returns the N-th (0-based) field of tuple t. TEST_F(BigTupleTest, get) { EXPECT_EQ(1, get<0>(a_)); EXPECT_EQ(2, get<9>(a_)); // Tests that get() works on a const tuple too. const BigTuple a(a_); EXPECT_EQ(1, get<0>(a)); EXPECT_EQ(2, get<9>(a)); } // Tests comparing big tuples. TEST_F(BigTupleTest, Comparisons) { EXPECT_TRUE(a_ == a_); EXPECT_FALSE(a_ != a_); EXPECT_TRUE(a_ != b_); EXPECT_FALSE(a_ == b_); } TEST(MakeTupleTest, WorksForScalarTypes) { tuple a; a = make_tuple(true, 5); EXPECT_TRUE(get<0>(a)); EXPECT_EQ(5, get<1>(a)); tuple b; b = make_tuple('a', 'b', 5); EXPECT_EQ('a', get<0>(b)); EXPECT_EQ('b', get<1>(b)); EXPECT_EQ(5, get<2>(b)); } TEST(MakeTupleTest, WorksForPointers) { int a[] = { 1, 2, 3, 4 }; const char* const str = "hi"; int* const p = a; tuple t; t = make_tuple(str, p); EXPECT_EQ(str, get<0>(t)); EXPECT_EQ(p, get<1>(t)); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-typed-test2_test.cc000066400000000000000000000040131273231111400307220ustar00rootroot00000000000000// 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 #include "test/gtest-typed-test_test.h" #include "gtest/gtest.h" #if GTEST_HAS_TYPED_TEST_P // Tests that the same type-parameterized test case can be // instantiated in different translation units linked together. // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest, testing::Types >); #endif // GTEST_HAS_TYPED_TEST_P mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-typed-test_test.cc000066400000000000000000000261511273231111400306470ustar00rootroot00000000000000// 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 #include #include "test/gtest-typed-test_test.h" #include "gtest/gtest.h" using testing::Test; // Used for testing that SetUpTestCase()/TearDownTestCase(), fixture // ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and // type-parameterized test. template class CommonTest : public Test { // For some technical reason, SetUpTestCase() and TearDownTestCase() // must be public. public: static void SetUpTestCase() { shared_ = new T(5); } static void TearDownTestCase() { delete shared_; shared_ = NULL; } // This 'protected:' is optional. There's no harm in making all // members of this fixture class template public. protected: // We used to use std::list here, but switched to std::vector since // MSVC's doesn't compile cleanly with /W4. typedef std::vector Vector; typedef std::set IntSet; CommonTest() : value_(1) {} virtual ~CommonTest() { EXPECT_EQ(3, value_); } virtual void SetUp() { EXPECT_EQ(1, value_); value_++; } virtual void TearDown() { EXPECT_EQ(2, value_); value_++; } T value_; static T* shared_; }; template T* CommonTest::shared_ = NULL; // This #ifdef block tests typed tests. #if GTEST_HAS_TYPED_TEST using testing::Types; // Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, // and SetUp()/TearDown() work correctly in typed tests typedef Types TwoTypes; TYPED_TEST_CASE(CommonTest, TwoTypes); TYPED_TEST(CommonTest, ValuesAreCorrect) { // Static members of the fixture class template can be visited via // the TestFixture:: prefix. EXPECT_EQ(5, *TestFixture::shared_); // Typedefs in the fixture class template can be visited via the // "typename TestFixture::" prefix. typename TestFixture::Vector empty; EXPECT_EQ(0U, empty.size()); typename TestFixture::IntSet empty2; EXPECT_EQ(0U, empty2.size()); // Non-static members of the fixture class must be visited via // 'this', as required by C++ for class templates. EXPECT_EQ(2, this->value_); } // The second test makes sure shared_ is not deleted after the first // test. TYPED_TEST(CommonTest, ValuesAreStillCorrect) { // Static members of the fixture class template can also be visited // via 'this'. ASSERT_TRUE(this->shared_ != NULL); EXPECT_EQ(5, *this->shared_); // TypeParam can be used to refer to the type parameter. EXPECT_EQ(static_cast(2), this->value_); } // Tests that multiple TYPED_TEST_CASE's can be defined in the same // translation unit. template class TypedTest1 : public Test { }; // Verifies that the second argument of TYPED_TEST_CASE can be a // single type. TYPED_TEST_CASE(TypedTest1, int); TYPED_TEST(TypedTest1, A) {} template class TypedTest2 : public Test { }; // Verifies that the second argument of TYPED_TEST_CASE can be a // Types<...> type list. TYPED_TEST_CASE(TypedTest2, Types); // This also verifies that tests from different typed test cases can // share the same name. TYPED_TEST(TypedTest2, A) {} // Tests that a typed test case can be defined in a namespace. namespace library1 { template class NumericTest : public Test { }; typedef Types NumericTypes; TYPED_TEST_CASE(NumericTest, NumericTypes); TYPED_TEST(NumericTest, DefaultIsZero) { EXPECT_EQ(0, TypeParam()); } } // namespace library1 #endif // GTEST_HAS_TYPED_TEST // This #ifdef block tests type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P using testing::Types; using testing::internal::TypedTestCasePState; // Tests TypedTestCasePState. class TypedTestCasePStateTest : public Test { protected: virtual void SetUp() { state_.AddTestName("foo.cc", 0, "FooTest", "A"); state_.AddTestName("foo.cc", 0, "FooTest", "B"); state_.AddTestName("foo.cc", 0, "FooTest", "C"); } TypedTestCasePState state_; }; TEST_F(TypedTestCasePStateTest, SucceedsForMatchingList) { const char* tests = "A, B, C"; EXPECT_EQ(tests, state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); } // Makes sure that the order of the tests and spaces around the names // don't matter. TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces) { const char* tests = "A,C, B"; EXPECT_EQ(tests, state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); } typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest; TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"), "foo\\.cc.1.?: Test A is listed more than once\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"), "foo\\.cc.1.?: No test named D can be found in this test case\\."); } TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) { EXPECT_DEATH_IF_SUPPORTED( state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"), "foo\\.cc.1.?: You forgot to list test B\\."); } // Tests that defining a test for a parameterized test case generates // a run-time error if the test case has been registered. TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration) { state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C"); EXPECT_DEATH_IF_SUPPORTED( state_.AddTestName("foo.cc", 2, "FooTest", "D"), "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P" "\\(FooTest, \\.\\.\\.\\)\\."); } // Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor, // and SetUp()/TearDown() work correctly in type-parameterized tests. template class DerivedTest : public CommonTest { }; TYPED_TEST_CASE_P(DerivedTest); TYPED_TEST_P(DerivedTest, ValuesAreCorrect) { // Static members of the fixture class template can be visited via // the TestFixture:: prefix. EXPECT_EQ(5, *TestFixture::shared_); // Non-static members of the fixture class must be visited via // 'this', as required by C++ for class templates. EXPECT_EQ(2, this->value_); } // The second test makes sure shared_ is not deleted after the first // test. TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect) { // Static members of the fixture class template can also be visited // via 'this'. ASSERT_TRUE(this->shared_ != NULL); EXPECT_EQ(5, *this->shared_); EXPECT_EQ(2, this->value_); } REGISTER_TYPED_TEST_CASE_P(DerivedTest, ValuesAreCorrect, ValuesAreStillCorrect); typedef Types MyTwoTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes); // Tests that multiple TYPED_TEST_CASE_P's can be defined in the same // translation unit. template class TypedTestP1 : public Test { }; TYPED_TEST_CASE_P(TypedTestP1); // For testing that the code between TYPED_TEST_CASE_P() and // TYPED_TEST_P() is not enclosed in a namespace. typedef int IntAfterTypedTestCaseP; TYPED_TEST_P(TypedTestP1, A) {} TYPED_TEST_P(TypedTestP1, B) {} // For testing that the code between TYPED_TEST_P() and // REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. typedef int IntBeforeRegisterTypedTestCaseP; REGISTER_TYPED_TEST_CASE_P(TypedTestP1, A, B); template class TypedTestP2 : public Test { }; TYPED_TEST_CASE_P(TypedTestP2); // This also verifies that tests from different type-parameterized // test cases can share the same name. TYPED_TEST_P(TypedTestP2, A) {} REGISTER_TYPED_TEST_CASE_P(TypedTestP2, A); // Verifies that the code between TYPED_TEST_CASE_P() and // REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace. IntAfterTypedTestCaseP after = 0; IntBeforeRegisterTypedTestCaseP before = 0; // Verifies that the last argument of INSTANTIATE_TYPED_TEST_CASE_P() // can be either a single type or a Types<...> type list. INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP1, int); INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP2, Types); // Tests that the same type-parameterized test case can be // instantiated more than once in the same translation unit. INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types); // Tests that the same type-parameterized test case can be // instantiated in different translation units linked together. // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) typedef Types, std::set > MyContainers; INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers); // Tests that a type-parameterized test case can be defined and // instantiated in a namespace. namespace library2 { template class NumericTest : public Test { }; TYPED_TEST_CASE_P(NumericTest); TYPED_TEST_P(NumericTest, DefaultIsZero) { EXPECT_EQ(0, TypeParam()); } TYPED_TEST_P(NumericTest, ZeroIsLessThanOne) { EXPECT_LT(TypeParam(0), TypeParam(1)); } REGISTER_TYPED_TEST_CASE_P(NumericTest, DefaultIsZero, ZeroIsLessThanOne); typedef Types NumericTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes); } // namespace library2 #endif // GTEST_HAS_TYPED_TEST_P #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) // Google Test may not support type-parameterized tests with some // compilers. If we use conditional compilation to compile out all // code referring to the gtest_main library, MSVC linker will not link // that library at all and consequently complain about missing entry // point defined in that library (fatal error LNK1561: entry point // must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} #endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-typed-test_test.h000066400000000000000000000046651273231111400305170ustar00rootroot00000000000000// 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_TEST_GTEST_TYPED_TEST_TEST_H_ #define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ #include "gtest/gtest.h" #if GTEST_HAS_TYPED_TEST_P using testing::Test; // For testing that the same type-parameterized test case can be // instantiated in different translation units linked together. // ContainerTest will be instantiated in both gtest-typed-test_test.cc // and gtest-typed-test2_test.cc. template class ContainerTest : public Test { }; TYPED_TEST_CASE_P(ContainerTest); TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) { TypeParam container; } TYPED_TEST_P(ContainerTest, InitialSizeIsZero) { TypeParam container; EXPECT_EQ(0U, container.size()); } REGISTER_TYPED_TEST_CASE_P(ContainerTest, CanBeDefaultConstructed, InitialSizeIsZero); #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest-unittest-api_test.cc000066400000000000000000000316271273231111400311770ustar00rootroot00000000000000// Copyright 2009 Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // // The Google C++ Testing Framework (Google Test) // // This file contains tests verifying correctness of data provided via // UnitTest's public methods. #include "gtest/gtest.h" #include // For strcmp. #include using ::testing::InitGoogleTest; namespace testing { namespace internal { template struct LessByName { bool operator()(const T* a, const T* b) { return strcmp(a->name(), b->name()) < 0; } }; class UnitTestHelper { public: // Returns the array of pointers to all test cases sorted by the test case // name. The caller is responsible for deleting the array. static TestCase const** const GetSortedTestCases() { UnitTest& unit_test = *UnitTest::GetInstance(); TestCase const** const test_cases = new const TestCase*[unit_test.total_test_case_count()]; for (int i = 0; i < unit_test.total_test_case_count(); ++i) test_cases[i] = unit_test.GetTestCase(i); std::sort(test_cases, test_cases + unit_test.total_test_case_count(), LessByName()); return test_cases; } // Returns the test case by its name. The caller doesn't own the returned // pointer. static const TestCase* FindTestCase(const char* name) { UnitTest& unit_test = *UnitTest::GetInstance(); for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase* test_case = unit_test.GetTestCase(i); if (0 == strcmp(test_case->name(), name)) return test_case; } return NULL; } // Returns the array of pointers to all tests in a particular test case // sorted by the test name. The caller is responsible for deleting the // array. static TestInfo const** const GetSortedTests(const TestCase* test_case) { TestInfo const** const tests = new const TestInfo*[test_case->total_test_count()]; for (int i = 0; i < test_case->total_test_count(); ++i) tests[i] = test_case->GetTestInfo(i); std::sort(tests, tests + test_case->total_test_count(), LessByName()); return tests; } }; #if GTEST_HAS_TYPED_TEST template class TestCaseWithCommentTest : public Test {}; TYPED_TEST_CASE(TestCaseWithCommentTest, Types); TYPED_TEST(TestCaseWithCommentTest, Dummy) {} const int kTypedTestCases = 1; const int kTypedTests = 1; #else const int kTypedTestCases = 0; const int kTypedTests = 0; #endif // GTEST_HAS_TYPED_TEST // We can only test the accessors that do not change value while tests run. // Since tests can be run in any order, the values the accessors that track // test execution (such as failed_test_count) can not be predicted. TEST(ApiTest, UnitTestImmutableAccessorsWork) { UnitTest* unit_test = UnitTest::GetInstance(); ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count()); EXPECT_EQ(2, unit_test->disabled_test_count()); EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count()); EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count()); const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); #if GTEST_HAS_TYPED_TEST EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); #endif // GTEST_HAS_TYPED_TEST delete[] test_cases; // The following lines initiate actions to verify certain methods in // FinalSuccessChecker::TearDown. // Records a test property to verify TestResult::GetTestProperty(). RecordProperty("key", "value"); } AssertionResult IsNull(const char* str) { if (str != NULL) { return testing::AssertionFailure() << "argument is " << str; } return AssertionSuccess(); } TEST(ApiTest, TestCaseImmutableAccessorsWork) { const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("ApiTest", test_case->name()); EXPECT_TRUE(IsNull(test_case->type_param())); EXPECT_TRUE(test_case->should_run()); EXPECT_EQ(1, test_case->disabled_test_count()); EXPECT_EQ(3, test_case->test_to_run_count()); ASSERT_EQ(4, test_case->total_test_count()); const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); EXPECT_TRUE(IsNull(tests[0]->value_param())); EXPECT_TRUE(IsNull(tests[0]->type_param())); EXPECT_FALSE(tests[0]->should_run()); EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); EXPECT_TRUE(IsNull(tests[1]->value_param())); EXPECT_TRUE(IsNull(tests[1]->type_param())); EXPECT_TRUE(tests[1]->should_run()); EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); EXPECT_TRUE(IsNull(tests[2]->value_param())); EXPECT_TRUE(IsNull(tests[2]->type_param())); EXPECT_TRUE(tests[2]->should_run()); EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); EXPECT_TRUE(IsNull(tests[3]->value_param())); EXPECT_TRUE(IsNull(tests[3]->type_param())); EXPECT_TRUE(tests[3]->should_run()); delete[] tests; tests = NULL; #if GTEST_HAS_TYPED_TEST test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name()); EXPECT_STREQ(GetTypeName().c_str(), test_case->type_param()); EXPECT_TRUE(test_case->should_run()); EXPECT_EQ(0, test_case->disabled_test_count()); EXPECT_EQ(1, test_case->test_to_run_count()); ASSERT_EQ(1, test_case->total_test_count()); tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); EXPECT_TRUE(IsNull(tests[0]->value_param())); EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); EXPECT_TRUE(tests[0]->should_run()); delete[] tests; #endif // GTEST_HAS_TYPED_TEST } TEST(ApiTest, TestCaseDisabledAccessorsWork) { const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("DISABLED_Test", test_case->name()); EXPECT_TRUE(IsNull(test_case->type_param())); EXPECT_FALSE(test_case->should_run()); EXPECT_EQ(1, test_case->disabled_test_count()); EXPECT_EQ(0, test_case->test_to_run_count()); ASSERT_EQ(1, test_case->total_test_count()); const TestInfo* const test_info = test_case->GetTestInfo(0); EXPECT_STREQ("Dummy2", test_info->name()); EXPECT_STREQ("DISABLED_Test", test_info->test_case_name()); EXPECT_TRUE(IsNull(test_info->value_param())); EXPECT_TRUE(IsNull(test_info->type_param())); EXPECT_FALSE(test_info->should_run()); } // These two tests are here to provide support for testing // test_case_to_run_count, disabled_test_count, and test_to_run_count. TEST(ApiTest, DISABLED_Dummy1) {} TEST(DISABLED_Test, Dummy2) {} class FinalSuccessChecker : public Environment { protected: virtual void TearDown() { UnitTest* unit_test = UnitTest::GetInstance(); EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count()); EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count()); EXPECT_EQ(0, unit_test->failed_test_case_count()); EXPECT_EQ(0, unit_test->failed_test_count()); EXPECT_TRUE(unit_test->Passed()); EXPECT_FALSE(unit_test->Failed()); ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count()); const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases(); EXPECT_STREQ("ApiTest", test_cases[0]->name()); EXPECT_TRUE(IsNull(test_cases[0]->type_param())); EXPECT_TRUE(test_cases[0]->should_run()); EXPECT_EQ(1, test_cases[0]->disabled_test_count()); ASSERT_EQ(4, test_cases[0]->total_test_count()); EXPECT_EQ(3, test_cases[0]->successful_test_count()); EXPECT_EQ(0, test_cases[0]->failed_test_count()); EXPECT_TRUE(test_cases[0]->Passed()); EXPECT_FALSE(test_cases[0]->Failed()); EXPECT_STREQ("DISABLED_Test", test_cases[1]->name()); EXPECT_TRUE(IsNull(test_cases[1]->type_param())); EXPECT_FALSE(test_cases[1]->should_run()); EXPECT_EQ(1, test_cases[1]->disabled_test_count()); ASSERT_EQ(1, test_cases[1]->total_test_count()); EXPECT_EQ(0, test_cases[1]->successful_test_count()); EXPECT_EQ(0, test_cases[1]->failed_test_count()); #if GTEST_HAS_TYPED_TEST EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name()); EXPECT_STREQ(GetTypeName().c_str(), test_cases[2]->type_param()); EXPECT_TRUE(test_cases[2]->should_run()); EXPECT_EQ(0, test_cases[2]->disabled_test_count()); ASSERT_EQ(1, test_cases[2]->total_test_count()); EXPECT_EQ(1, test_cases[2]->successful_test_count()); EXPECT_EQ(0, test_cases[2]->failed_test_count()); EXPECT_TRUE(test_cases[2]->Passed()); EXPECT_FALSE(test_cases[2]->Failed()); #endif // GTEST_HAS_TYPED_TEST const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); EXPECT_STREQ("ApiTest", tests[0]->test_case_name()); EXPECT_FALSE(tests[0]->should_run()); EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); EXPECT_TRUE(IsNull(tests[1]->value_param())); EXPECT_TRUE(IsNull(tests[1]->type_param())); EXPECT_TRUE(tests[1]->should_run()); EXPECT_TRUE(tests[1]->result()->Passed()); EXPECT_EQ(0, tests[1]->result()->test_property_count()); EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); EXPECT_TRUE(IsNull(tests[2]->value_param())); EXPECT_TRUE(IsNull(tests[2]->type_param())); EXPECT_TRUE(tests[2]->should_run()); EXPECT_TRUE(tests[2]->result()->Passed()); EXPECT_EQ(0, tests[2]->result()->test_property_count()); EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); EXPECT_TRUE(IsNull(tests[3]->value_param())); EXPECT_TRUE(IsNull(tests[3]->type_param())); EXPECT_TRUE(tests[3]->should_run()); EXPECT_TRUE(tests[3]->result()->Passed()); EXPECT_EQ(1, tests[3]->result()->test_property_count()); const TestProperty& property = tests[3]->result()->GetTestProperty(0); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value", property.value()); delete[] tests; #if GTEST_HAS_TYPED_TEST test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0"); tests = UnitTestHelper::GetSortedTests(test_case); EXPECT_STREQ("Dummy", tests[0]->name()); EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name()); EXPECT_TRUE(IsNull(tests[0]->value_param())); EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); EXPECT_TRUE(tests[0]->should_run()); EXPECT_TRUE(tests[0]->result()->Passed()); EXPECT_EQ(0, tests[0]->result()->test_property_count()); delete[] tests; #endif // GTEST_HAS_TYPED_TEST delete[] test_cases; } }; } // namespace internal } // namespace testing int main(int argc, char **argv) { InitGoogleTest(&argc, argv); AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker()); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_all_test.cc000066400000000000000000000043131273231111400273730ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Tests for Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build most of Google Test's own tests // by compiling a single file. This file serves this purpose. #include "test/gtest-filepath_test.cc" #include "test/gtest-linked_ptr_test.cc" #include "test/gtest-message_test.cc" #include "test/gtest-options_test.cc" #include "test/gtest-port_test.cc" #include "test/gtest_pred_impl_unittest.cc" #include "test/gtest_prod_test.cc" #include "test/gtest-test-part_test.cc" #include "test/gtest-typed-test_test.cc" #include "test/gtest-typed-test2_test.cc" #include "test/gtest_unittest.cc" #include "test/production.cc" mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_break_on_failure_unittest.py000077500000000000000000000162531273231111400330660ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test for Google Test's break-on-failure mode. A user can ask Google Test to seg-fault when an assertion fails, using either the GTEST_BREAK_ON_FAILURE environment variable or the --gtest_break_on_failure flag. This script tests such functionality by invoking gtest_break_on_failure_unittest_ (a program written with Google Test) with different environments and command line flags. """ __author__ = 'wan@google.com (Zhanyong Wan)' import gtest_test_utils import os import sys # Constants. IS_WINDOWS = os.name == 'nt' # The environment variable for enabling/disabling the break-on-failure mode. BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE' # The command line flag for enabling/disabling the break-on-failure mode. BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure' # The environment variable for enabling/disabling the throw-on-failure mode. THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE' # The environment variable for enabling/disabling the catch-exceptions mode. CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS' # Path to the gtest_break_on_failure_unittest_ program. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_break_on_failure_unittest_') environ = gtest_test_utils.environ SetEnvVar = gtest_test_utils.SetEnvVar # Tests in this file run a Google-Test-based test program and expect it # to terminate prematurely. Therefore they are incompatible with # the premature-exit-file protocol by design. Unset the # premature-exit filepath to prevent Google Test from creating # the file. SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) def Run(command): """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise.""" p = gtest_test_utils.Subprocess(command, env=environ) if p.terminated_by_signal: return 1 else: return 0 # The tests. class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase): """Tests using the GTEST_BREAK_ON_FAILURE environment variable or the --gtest_break_on_failure flag to turn assertion failures into segmentation faults. """ def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault): """Runs gtest_break_on_failure_unittest_ and verifies that it does (or does not) have a seg-fault. Args: env_var_value: value of the GTEST_BREAK_ON_FAILURE environment variable; None if the variable should be unset. flag_value: value of the --gtest_break_on_failure flag; None if the flag should not be present. expect_seg_fault: 1 if the program is expected to generate a seg-fault; 0 otherwise. """ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value) if env_var_value is None: env_var_value_msg = ' is not set' else: env_var_value_msg = '=' + env_var_value if flag_value is None: flag = '' elif flag_value == '0': flag = '--%s=0' % BREAK_ON_FAILURE_FLAG else: flag = '--%s' % BREAK_ON_FAILURE_FLAG command = [EXE_PATH] if flag: command.append(flag) if expect_seg_fault: should_or_not = 'should' else: should_or_not = 'should not' has_seg_fault = Run(command) SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None) msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' % (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command), should_or_not)) self.assert_(has_seg_fault == expect_seg_fault, msg) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(env_var_value=None, flag_value=None, expect_seg_fault=0) def testEnvVar(self): """Tests using the GTEST_BREAK_ON_FAILURE environment variable.""" self.RunAndVerify(env_var_value='0', flag_value=None, expect_seg_fault=0) self.RunAndVerify(env_var_value='1', flag_value=None, expect_seg_fault=1) def testFlag(self): """Tests using the --gtest_break_on_failure flag.""" self.RunAndVerify(env_var_value=None, flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value=None, flag_value='1', expect_seg_fault=1) def testFlagOverridesEnvVar(self): """Tests that the flag overrides the environment variable.""" self.RunAndVerify(env_var_value='0', flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value='0', flag_value='1', expect_seg_fault=1) self.RunAndVerify(env_var_value='1', flag_value='0', expect_seg_fault=0) self.RunAndVerify(env_var_value='1', flag_value='1', expect_seg_fault=1) def testBreakOnFailureOverridesThrowOnFailure(self): """Tests that gtest_break_on_failure overrides gtest_throw_on_failure.""" SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1') try: self.RunAndVerify(env_var_value=None, flag_value='1', expect_seg_fault=1) finally: SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None) if IS_WINDOWS: def testCatchExceptionsDoesNotInterfere(self): """Tests that gtest_catch_exceptions doesn't interfere.""" SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1') try: self.RunAndVerify(env_var_value='1', flag_value='1', expect_seg_fault=1) finally: SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_break_on_failure_unittest_.cc000066400000000000000000000062771273231111400331640ustar00rootroot00000000000000// 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) // Unit test for Google Test's break-on-failure mode. // // A user can ask Google Test to seg-fault when an assertion fails, using // either the GTEST_BREAK_ON_FAILURE environment variable or the // --gtest_break_on_failure flag. This file is used for testing such // functionality. // // This program will be invoked from a Python unit test. It is // expected to fail. Don't run it directly. #include "gtest/gtest.h" #if GTEST_OS_WINDOWS # include # include #endif namespace { // A test that's expected to fail. TEST(Foo, Bar) { EXPECT_EQ(2, 3); } #if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE // On Windows Mobile global exception handlers are not supported. LONG WINAPI ExitWithExceptionCode( struct _EXCEPTION_POINTERS* exception_pointers) { exit(exception_pointers->ExceptionRecord->ExceptionCode); } #endif } // namespace int main(int argc, char **argv) { #if GTEST_OS_WINDOWS // Suppresses display of the Windows error dialog upon encountering // a general protection fault (segment violation). SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); # if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE // The default unhandled exception filter does not always exit // with the exception code as exit code - for example it exits with // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT // if the application is compiled in debug mode. Thus we use our own // filter which always exits with the exception code for unhandled // exceptions. SetUnhandledExceptionFilter(ExitWithExceptionCode); # endif #endif testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_catch_exceptions_test.py000077500000000000000000000232551273231111400322220ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2010 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. """Tests Google Test's exception catching behavior. This script invokes gtest_catch_exceptions_test_ and gtest_catch_exceptions_ex_test_ (programs written with Google Test) and verifies their output. """ __author__ = 'vladl@google.com (Vlad Losev)' import os import gtest_test_utils # Constants. FLAG_PREFIX = '--gtest_' LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' NO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0' FILTER_FLAG = FLAG_PREFIX + 'filter' # Path to the gtest_catch_exceptions_ex_test_ binary, compiled with # exceptions enabled. EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_catch_exceptions_ex_test_') # Path to the gtest_catch_exceptions_test_ binary, compiled with # exceptions disabled. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_catch_exceptions_no_ex_test_') environ = gtest_test_utils.environ SetEnvVar = gtest_test_utils.SetEnvVar # Tests in this file run a Google-Test-based test program and expect it # to terminate prematurely. Therefore they are incompatible with # the premature-exit-file protocol by design. Unset the # premature-exit filepath to prevent Google Test from creating # the file. SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) TEST_LIST = gtest_test_utils.Subprocess( [EXE_PATH, LIST_TESTS_FLAG], env=environ).output SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST if SUPPORTS_SEH_EXCEPTIONS: BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH], env=environ).output EX_BINARY_OUTPUT = gtest_test_utils.Subprocess( [EX_EXE_PATH], env=environ).output # The tests. if SUPPORTS_SEH_EXCEPTIONS: # pylint:disable-msg=C6302 class CatchSehExceptionsTest(gtest_test_utils.TestCase): """Tests exception-catching behavior.""" def TestSehExceptions(self, test_output): self.assert_('SEH exception with code 0x2a thrown ' 'in the test fixture\'s constructor' in test_output) self.assert_('SEH exception with code 0x2a thrown ' 'in the test fixture\'s destructor' in test_output) self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()' in test_output) self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()' in test_output) self.assert_('SEH exception with code 0x2a thrown in SetUp()' in test_output) self.assert_('SEH exception with code 0x2a thrown in TearDown()' in test_output) self.assert_('SEH exception with code 0x2a thrown in the test body' in test_output) def testCatchesSehExceptionsWithCxxExceptionsEnabled(self): self.TestSehExceptions(EX_BINARY_OUTPUT) def testCatchesSehExceptionsWithCxxExceptionsDisabled(self): self.TestSehExceptions(BINARY_OUTPUT) class CatchCxxExceptionsTest(gtest_test_utils.TestCase): """Tests C++ exception-catching behavior. Tests in this test case verify that: * C++ exceptions are caught and logged as C++ (not SEH) exceptions * Exception thrown affect the remainder of the test work flow in the expected manner. """ def testCatchesCxxExceptionsInFixtureConstructor(self): self.assert_('C++ exception with description ' '"Standard C++ exception" thrown ' 'in the test fixture\'s constructor' in EX_BINARY_OUTPUT) self.assert_('unexpected' not in EX_BINARY_OUTPUT, 'This failure belongs in this test only if ' '"CxxExceptionInConstructorTest" (no quotes) ' 'appears on the same line as words "called unexpectedly"') if ('CxxExceptionInDestructorTest.ThrowsExceptionInDestructor' in EX_BINARY_OUTPUT): def testCatchesCxxExceptionsInFixtureDestructor(self): self.assert_('C++ exception with description ' '"Standard C++ exception" thrown ' 'in the test fixture\'s destructor' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInSetUpTestCase(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in SetUpTestCase()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest constructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest test body ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInTearDownTestCase(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in TearDownTestCase()' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInSetUp(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in SetUp()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('unexpected' not in EX_BINARY_OUTPUT, 'This failure belongs in this test only if ' '"CxxExceptionInSetUpTest" (no quotes) ' 'appears on the same line as words "called unexpectedly"') def testCatchesCxxExceptionsInTearDown(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in TearDown()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTearDownTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInTestBody(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in the test body' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesNonStdCxxExceptions(self): self.assert_('Unknown C++ exception thrown in the test body' in EX_BINARY_OUTPUT) def testUnhandledCxxExceptionsAbortTheProgram(self): # Filters out SEH exception tests on Windows. Unhandled SEH exceptions # cause tests to show pop-up windows there. FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*' # By default, Google Test doesn't catch the exceptions. uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess( [EX_EXE_PATH, NO_CATCH_EXCEPTIONS_FLAG, FITLER_OUT_SEH_TESTS_FLAG], env=environ).output self.assert_('Unhandled C++ exception terminating the program' in uncaught_exceptions_ex_binary_output) self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_catch_exceptions_test_.cc000066400000000000000000000213271273231111400323110ustar00rootroot00000000000000// Copyright 2010, 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) // // Tests for Google Test itself. Tests in this file throw C++ or SEH // exceptions, and the output is verified by gtest_catch_exceptions_test.py. #include "gtest/gtest.h" #include // NOLINT #include // For exit(). #if GTEST_HAS_SEH # include #endif #if GTEST_HAS_EXCEPTIONS # include // For set_terminate(). # include #endif using testing::Test; #if GTEST_HAS_SEH class SehExceptionInConstructorTest : public Test { public: SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {} class SehExceptionInDestructorTest : public Test { public: ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {} class SehExceptionInSetUpTestCaseTest : public Test { public: static void SetUpTestCase() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {} class SehExceptionInTearDownTestCaseTest : public Test { public: static void TearDownTestCase() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} class SehExceptionInSetUpTest : public Test { protected: virtual void SetUp() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {} class SehExceptionInTearDownTest : public Test { protected: virtual void TearDown() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {} TEST(SehExceptionTest, ThrowsSehException) { RaiseException(42, 0, 0, NULL); } #endif // GTEST_HAS_SEH #if GTEST_HAS_EXCEPTIONS class CxxExceptionInConstructorTest : public Test { public: CxxExceptionInConstructorTest() { // Without this macro VC++ complains about unreachable code at the end of // the constructor. GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( throw std::runtime_error("Standard C++ exception")); } static void TearDownTestCase() { printf("%s", "CxxExceptionInConstructorTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInConstructorTest() { ADD_FAILURE() << "CxxExceptionInConstructorTest destructor " << "called unexpectedly."; } virtual void SetUp() { ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() " << "called unexpectedly."; } virtual void TearDown() { ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() " << "called unexpectedly."; } }; TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor) { ADD_FAILURE() << "CxxExceptionInConstructorTest test body " << "called unexpectedly."; } // Exceptions in destructors are not supported in C++11. #if !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L class CxxExceptionInDestructorTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInDestructorTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInDestructorTest() { GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( throw std::runtime_error("Standard C++ exception")); } }; TEST_F(CxxExceptionInDestructorTest, ThrowsExceptionInDestructor) {} #endif // C++11 mode class CxxExceptionInSetUpTestCaseTest : public Test { public: CxxExceptionInSetUpTestCaseTest() { printf("%s", "CxxExceptionInSetUpTestCaseTest constructor " "called as expected.\n"); } static void SetUpTestCase() { throw std::runtime_error("Standard C++ exception"); } static void TearDownTestCase() { printf("%s", "CxxExceptionInSetUpTestCaseTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInSetUpTestCaseTest() { printf("%s", "CxxExceptionInSetUpTestCaseTest destructor " "called as expected.\n"); } virtual void SetUp() { printf("%s", "CxxExceptionInSetUpTestCaseTest::SetUp() " "called as expected.\n"); } virtual void TearDown() { printf("%s", "CxxExceptionInSetUpTestCaseTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) { printf("%s", "CxxExceptionInSetUpTestCaseTest test body " "called as expected.\n"); } class CxxExceptionInTearDownTestCaseTest : public Test { public: static void TearDownTestCase() { throw std::runtime_error("Standard C++ exception"); } }; TEST_F(CxxExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} class CxxExceptionInSetUpTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInSetUpTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInSetUpTest() { printf("%s", "CxxExceptionInSetUpTest destructor " "called as expected.\n"); } virtual void SetUp() { throw std::runtime_error("Standard C++ exception"); } virtual void TearDown() { printf("%s", "CxxExceptionInSetUpTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp) { ADD_FAILURE() << "CxxExceptionInSetUpTest test body " << "called unexpectedly."; } class CxxExceptionInTearDownTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInTearDownTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInTearDownTest() { printf("%s", "CxxExceptionInTearDownTest destructor " "called as expected.\n"); } virtual void TearDown() { throw std::runtime_error("Standard C++ exception"); } }; TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {} class CxxExceptionInTestBodyTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInTestBodyTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInTestBodyTest() { printf("%s", "CxxExceptionInTestBodyTest destructor " "called as expected.\n"); } virtual void TearDown() { printf("%s", "CxxExceptionInTestBodyTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException) { throw std::runtime_error("Standard C++ exception"); } TEST(CxxExceptionTest, ThrowsNonStdCxxException) { throw "C-string"; } // This terminate handler aborts the program using exit() rather than abort(). // This avoids showing pop-ups on Windows systems and core dumps on Unix-like // ones. void TerminateHandler() { fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); fflush(NULL); exit(3); } #endif // GTEST_HAS_EXCEPTIONS int main(int argc, char** argv) { #if GTEST_HAS_EXCEPTIONS std::set_terminate(&TerminateHandler); #endif testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_color_test.py000077500000000000000000000114571273231111400300160ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Verifies that Google Test correctly determines whether to use colors.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils IS_WINDOWS = os.name = 'nt' COLOR_ENV_VAR = 'GTEST_COLOR' COLOR_FLAG = 'gtest_color' COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_color_test_') def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: os.environ[env_var] = value elif env_var in os.environ: del os.environ[env_var] def UsesColor(term, color_env_var, color_flag): """Runs gtest_color_test_ and returns its exit code.""" SetEnvVar('TERM', term) SetEnvVar(COLOR_ENV_VAR, color_env_var) if color_flag is None: args = [] else: args = ['--%s=%s' % (COLOR_FLAG, color_flag)] p = gtest_test_utils.Subprocess([COMMAND] + args) return not p.exited or p.exit_code class GTestColorTest(gtest_test_utils.TestCase): def testNoEnvVarNoFlag(self): """Tests the case when there's neither GTEST_COLOR nor --gtest_color.""" if not IS_WINDOWS: self.assert_(not UsesColor('dumb', None, None)) self.assert_(not UsesColor('emacs', None, None)) self.assert_(not UsesColor('xterm-mono', None, None)) self.assert_(not UsesColor('unknown', None, None)) self.assert_(not UsesColor(None, None, None)) self.assert_(UsesColor('linux', None, None)) self.assert_(UsesColor('cygwin', None, None)) self.assert_(UsesColor('xterm', None, None)) self.assert_(UsesColor('xterm-color', None, None)) self.assert_(UsesColor('xterm-256color', None, None)) def testFlagOnly(self): """Tests the case when there's --gtest_color but not GTEST_COLOR.""" self.assert_(not UsesColor('dumb', None, 'no')) self.assert_(not UsesColor('xterm-color', None, 'no')) if not IS_WINDOWS: self.assert_(not UsesColor('emacs', None, 'auto')) self.assert_(UsesColor('xterm', None, 'auto')) self.assert_(UsesColor('dumb', None, 'yes')) self.assert_(UsesColor('xterm', None, 'yes')) def testEnvVarOnly(self): """Tests the case when there's GTEST_COLOR but not --gtest_color.""" self.assert_(not UsesColor('dumb', 'no', None)) self.assert_(not UsesColor('xterm-color', 'no', None)) if not IS_WINDOWS: self.assert_(not UsesColor('dumb', 'auto', None)) self.assert_(UsesColor('xterm-color', 'auto', None)) self.assert_(UsesColor('dumb', 'yes', None)) self.assert_(UsesColor('xterm-color', 'yes', None)) def testEnvVarAndFlag(self): """Tests the case when there are both GTEST_COLOR and --gtest_color.""" self.assert_(not UsesColor('xterm-color', 'no', 'no')) self.assert_(UsesColor('dumb', 'no', 'yes')) self.assert_(UsesColor('xterm-color', 'no', 'auto')) def testAliasesOfYesAndNo(self): """Tests using aliases in specifying --gtest_color.""" self.assert_(UsesColor('dumb', None, 'true')) self.assert_(UsesColor('dumb', None, 'YES')) self.assert_(UsesColor('dumb', None, 'T')) self.assert_(UsesColor('dumb', None, '1')) self.assert_(not UsesColor('xterm', None, 'f')) self.assert_(not UsesColor('xterm', None, 'false')) self.assert_(not UsesColor('xterm', None, '0')) self.assert_(not UsesColor('xterm', None, 'unknown')) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_color_test_.cc000066400000000000000000000055101273231111400301000ustar00rootroot00000000000000// 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) // A helper program for testing how Google Test determines whether to use // colors in the output. It prints "YES" and returns 1 if Google Test // decides to use colors, and prints "NO" and returns 0 otherwise. #include #include "gtest/gtest.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_ using testing::internal::ShouldUseColor; // The purpose of this is to ensure that the UnitTest singleton is // created before main() is entered, and thus that ShouldUseColor() // works the same way as in a real Google-Test-based test. We don't actual // run the TEST itself. TEST(GTestColorTest, Dummy) { } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); if (ShouldUseColor(true)) { // Google Test decides to use colors in the output (assuming it // goes to a TTY). printf("YES\n"); return 1; } else { // Google Test decides not to use colors in the output. printf("NO\n"); return 0; } } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_env_var_test.py000077500000000000000000000066371273231111400303440ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Verifies that Google Test correctly parses environment variables.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils IS_WINDOWS = os.name == 'nt' IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_env_var_test_') environ = os.environ.copy() def AssertEq(expected, actual): if expected != actual: print 'Expected: %s' % (expected,) print ' Actual: %s' % (actual,) raise AssertionError def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] def GetFlag(flag): """Runs gtest_env_var_test_ and returns its output.""" args = [COMMAND] if flag is not None: args += [flag] return gtest_test_utils.Subprocess(args, env=environ).output def TestFlag(flag, test_val, default_val): """Verifies that the given flag is affected by the corresponding env var.""" env_var = 'GTEST_' + flag.upper() SetEnvVar(env_var, test_val) AssertEq(test_val, GetFlag(flag)) SetEnvVar(env_var, None) AssertEq(default_val, GetFlag(flag)) class GTestEnvVarTest(gtest_test_utils.TestCase): def testEnvVarAffectsFlag(self): """Tests that environment variable should affect the corresponding flag.""" TestFlag('break_on_failure', '1', '0') TestFlag('color', 'yes', 'auto') TestFlag('filter', 'FooTest.Bar', '*') TestFlag('output', 'xml:tmp/foo.xml', '') TestFlag('print_time', '0', '1') TestFlag('repeat', '999', '1') TestFlag('throw_on_failure', '1', '0') TestFlag('death_test_style', 'threadsafe', 'fast') TestFlag('catch_exceptions', '0', '1') if IS_LINUX: TestFlag('death_test_use_fork', '1', '0') TestFlag('stack_trace_depth', '0', '100') if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_env_var_test_.cc000066400000000000000000000067701273231111400304330ustar00rootroot00000000000000// 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) // A helper program for testing that Google Test parses the environment // variables correctly. #include "gtest/gtest.h" #include #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ using ::std::cout; namespace testing { // The purpose of this is to make the test more realistic by ensuring // that the UnitTest singleton is created before main() is entered. // We don't actual run the TEST itself. TEST(GTestEnvVarTest, Dummy) { } void PrintFlag(const char* flag) { if (strcmp(flag, "break_on_failure") == 0) { cout << GTEST_FLAG(break_on_failure); return; } if (strcmp(flag, "catch_exceptions") == 0) { cout << GTEST_FLAG(catch_exceptions); return; } if (strcmp(flag, "color") == 0) { cout << GTEST_FLAG(color); return; } if (strcmp(flag, "death_test_style") == 0) { cout << GTEST_FLAG(death_test_style); return; } if (strcmp(flag, "death_test_use_fork") == 0) { cout << GTEST_FLAG(death_test_use_fork); return; } if (strcmp(flag, "filter") == 0) { cout << GTEST_FLAG(filter); return; } if (strcmp(flag, "output") == 0) { cout << GTEST_FLAG(output); return; } if (strcmp(flag, "print_time") == 0) { cout << GTEST_FLAG(print_time); return; } if (strcmp(flag, "repeat") == 0) { cout << GTEST_FLAG(repeat); return; } if (strcmp(flag, "stack_trace_depth") == 0) { cout << GTEST_FLAG(stack_trace_depth); return; } if (strcmp(flag, "throw_on_failure") == 0) { cout << GTEST_FLAG(throw_on_failure); return; } cout << "Invalid flag name " << flag << ". Valid names are break_on_failure, color, filter, etc.\n"; exit(1); } } // namespace testing int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); if (argc != 2) { cout << "Usage: gtest_env_var_test_ NAME_OF_FLAG\n"; return 1; } testing::PrintFlag(argv[1]); return 0; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_environment_test.cc000066400000000000000000000147161273231111400311770ustar00rootroot00000000000000// 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) // // Tests using global test environments. #include #include #include "gtest/gtest.h" #define GTEST_IMPLEMENTATION_ 1 // Required for the next #include. #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ namespace testing { GTEST_DECLARE_string_(filter); } namespace { enum FailureType { NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE }; // For testing using global test environments. class MyEnvironment : public testing::Environment { public: MyEnvironment() { Reset(); } // Depending on the value of failure_in_set_up_, SetUp() will // generate a non-fatal failure, generate a fatal failure, or // succeed. virtual void SetUp() { set_up_was_run_ = true; switch (failure_in_set_up_) { case NON_FATAL_FAILURE: ADD_FAILURE() << "Expected non-fatal failure in global set-up."; break; case FATAL_FAILURE: FAIL() << "Expected fatal failure in global set-up."; break; default: break; } } // Generates a non-fatal failure. virtual void TearDown() { tear_down_was_run_ = true; ADD_FAILURE() << "Expected non-fatal failure in global tear-down."; } // Resets the state of the environment s.t. it can be reused. void Reset() { failure_in_set_up_ = NO_FAILURE; set_up_was_run_ = false; tear_down_was_run_ = false; } // We call this function to set the type of failure SetUp() should // generate. void set_failure_in_set_up(FailureType type) { failure_in_set_up_ = type; } // Was SetUp() run? bool set_up_was_run() const { return set_up_was_run_; } // Was TearDown() run? bool tear_down_was_run() const { return tear_down_was_run_; } private: FailureType failure_in_set_up_; bool set_up_was_run_; bool tear_down_was_run_; }; // Was the TEST run? bool test_was_run; // The sole purpose of this TEST is to enable us to check whether it // was run. TEST(FooTest, Bar) { test_was_run = true; } // Prints the message and aborts the program if condition is false. void Check(bool condition, const char* msg) { if (!condition) { printf("FAILED: %s\n", msg); testing::internal::posix::Abort(); } } // Runs the tests. Return true iff successful. // // The 'failure' parameter specifies the type of failure that should // be generated by the global set-up. int RunAllTests(MyEnvironment* env, FailureType failure) { env->Reset(); env->set_failure_in_set_up(failure); test_was_run = false; testing::internal::GetUnitTestImpl()->ClearAdHocTestResult(); return RUN_ALL_TESTS(); } } // namespace int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); // Registers a global test environment, and verifies that the // registration function returns its argument. MyEnvironment* const env = new MyEnvironment; Check(testing::AddGlobalTestEnvironment(env) == env, "AddGlobalTestEnvironment() should return its argument."); // Verifies that RUN_ALL_TESTS() runs the tests when the global // set-up is successful. Check(RunAllTests(env, NO_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as the global tear-down " "should generate a failure."); Check(test_was_run, "The tests should run, as the global set-up should generate no " "failure"); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() runs the tests when the global // set-up generates no fatal failure. Check(RunAllTests(env, NON_FATAL_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as both the global set-up " "and the global tear-down should generate a non-fatal failure."); Check(test_was_run, "The tests should run, as the global set-up should generate no " "fatal failure."); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() runs no test when the global set-up // generates a fatal failure. Check(RunAllTests(env, FATAL_FAILURE) != 0, "RUN_ALL_TESTS() should return non-zero, as the global set-up " "should generate a fatal failure."); Check(!test_was_run, "The tests should not run, as the global set-up should generate " "a fatal failure."); Check(env->tear_down_was_run(), "The global tear-down should run, as the global set-up was run."); // Verifies that RUN_ALL_TESTS() doesn't do global set-up or // tear-down when there is no test to run. testing::GTEST_FLAG(filter) = "-*"; Check(RunAllTests(env, NO_FAILURE) == 0, "RUN_ALL_TESTS() should return zero, as there is no test to run."); Check(!env->set_up_was_run(), "The global set-up should not run, as there is no test to run."); Check(!env->tear_down_was_run(), "The global tear-down should not run, " "as the global set-up was not run."); printf("PASS\n"); return 0; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_filter_unittest.py000077500000000000000000000514151273231111400310630ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test for Google Test test filters. A user can specify which test(s) in a Google Test program to run via either the GTEST_FILTER environment variable or the --gtest_filter flag. This script tests such functionality by invoking gtest_filter_unittest_ (a program written with Google Test) with different environments and command line flags. Note that test sharding may also influence which tests are filtered. Therefore, we test that here also. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sets import sys import gtest_test_utils # Constants. # Checks if this platform can pass empty environment variables to child # processes. We set an env variable to an empty string and invoke a python # script in a subprocess to print whether the variable is STILL in # os.environ. We then use 'eval' to parse the child's output so that an # exception is thrown if the input is anything other than 'True' nor 'False'. os.environ['EMPTY_VAR'] = '' child = gtest_test_utils.Subprocess( [sys.executable, '-c', 'import os; print \'EMPTY_VAR\' in os.environ']) CAN_PASS_EMPTY_ENV = eval(child.output) # Check if this platform can unset environment variables in child processes. # We set an env variable to a non-empty string, unset it, and invoke # a python script in a subprocess to print whether the variable # is NO LONGER in os.environ. # We use 'eval' to parse the child's output so that an exception # is thrown if the input is neither 'True' nor 'False'. os.environ['UNSET_VAR'] = 'X' del os.environ['UNSET_VAR'] child = gtest_test_utils.Subprocess( [sys.executable, '-c', 'import os; print \'UNSET_VAR\' not in os.environ']) CAN_UNSET_ENV = eval(child.output) # Checks if we should test with an empty filter. This doesn't # make sense on platforms that cannot pass empty env variables (Win32) # and on platforms that cannot unset variables (since we cannot tell # the difference between "" and NULL -- Borland and Solaris < 5.10) CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV) # The environment variable for specifying the test filters. FILTER_ENV_VAR = 'GTEST_FILTER' # The environment variables for test sharding. TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' # The command line flag for specifying the test filters. FILTER_FLAG = 'gtest_filter' # The command line flag for including disabled tests. ALSO_RUN_DISABED_TESTS_FLAG = 'gtest_also_run_disabled_tests' # Command to run the gtest_filter_unittest_ program. COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_filter_unittest_') # Regex for determining whether parameterized tests are enabled in the binary. PARAM_TEST_REGEX = re.compile(r'/ParamTest') # Regex for parsing test case names from Google Test's output. TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)') # Regex for parsing test names from Google Test's output. TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)') # The command line flag to tell Google Test to output the list of tests it # will run. LIST_TESTS_FLAG = '--gtest_list_tests' # Indicates whether Google Test supports death tests. SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess( [COMMAND, LIST_TESTS_FLAG]).output # Full names of all tests in gtest_filter_unittests_. PARAM_TESTS = [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', 'SeqQ/ParamTest.TestX/0', 'SeqQ/ParamTest.TestX/1', 'SeqQ/ParamTest.TestY/0', 'SeqQ/ParamTest.TestY/1', ] DISABLED_TESTS = [ 'BarTest.DISABLED_TestFour', 'BarTest.DISABLED_TestFive', 'BazTest.DISABLED_TestC', 'DISABLED_FoobarTest.Test1', 'DISABLED_FoobarTest.DISABLED_Test2', 'DISABLED_FoobarbazTest.TestA', ] if SUPPORTS_DEATH_TESTS: DEATH_TESTS = [ 'HasDeathTest.Test1', 'HasDeathTest.Test2', ] else: DEATH_TESTS = [] # All the non-disabled tests. ACTIVE_TESTS = [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS param_tests_present = None # Utilities. environ = os.environ.copy() def SetEnvVar(env_var, value): """Sets the env variable to 'value'; unsets it when 'value' is None.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] def RunAndReturnOutput(args = None): """Runs the test program and returns its output.""" return gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ).output def RunAndExtractTestList(args = None): """Runs the test program and returns its exit code and a list of tests run.""" p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ) tests_run = [] test_case = '' test = '' for line in p.output.split('\n'): match = TEST_CASE_REGEX.match(line) if match is not None: test_case = match.group(1) else: match = TEST_REGEX.match(line) if match is not None: test = match.group(1) tests_run.append(test_case + '.' + test) return (tests_run, p.exit_code) def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs): """Runs the given function and arguments in a modified environment.""" try: original_env = environ.copy() environ.update(extra_env) return function(*args, **kwargs) finally: environ.clear() environ.update(original_env) def RunWithSharding(total_shards, shard_index, command): """Runs a test program shard and returns exit code and a list of tests run.""" extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index), TOTAL_SHARDS_ENV_VAR: str(total_shards)} return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command) # The unit test. class GTestFilterUnitTest(gtest_test_utils.TestCase): """Tests the env variable or the command line flag to filter tests.""" # Utilities. def AssertSetEqual(self, lhs, rhs): """Asserts that two sets are equal.""" for elem in lhs: self.assert_(elem in rhs, '%s in %s' % (elem, rhs)) for elem in rhs: self.assert_(elem in lhs, '%s in %s' % (elem, lhs)) def AssertPartitionIsValid(self, set_var, list_of_sets): """Asserts that list_of_sets is a valid partition of set_var.""" full_partition = [] for slice_var in list_of_sets: full_partition.extend(slice_var) self.assertEqual(len(set_var), len(full_partition)) self.assertEqual(sets.Set(set_var), sets.Set(full_partition)) def AdjustForParameterizedTests(self, tests_to_run): """Adjust tests_to_run in case value parameterized tests are disabled.""" global param_tests_present if not param_tests_present: return list(sets.Set(tests_to_run) - sets.Set(PARAM_TESTS)) else: return tests_to_run def RunAndVerify(self, gtest_filter, tests_to_run): """Checks that the binary runs correct set of tests for a given filter.""" tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # First, tests using the environment variable. # Windows removes empty variables from the environment when passing it # to a new process. This means it is impossible to pass an empty filter # into a process using the environment variable. However, we can still # test the case when the variable is not supplied (i.e., gtest_filter is # None). # pylint: disable-msg=C6403 if CAN_TEST_EMPTY_FILTER or gtest_filter != '': SetEnvVar(FILTER_ENV_VAR, gtest_filter) tests_run = RunAndExtractTestList()[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, tests_to_run) # pylint: enable-msg=C6403 # Next, tests using the command line flag. if gtest_filter is None: args = [] else: args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)] tests_run = RunAndExtractTestList(args)[0] self.AssertSetEqual(tests_run, tests_to_run) def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run, args=None, check_exit_0=False): """Checks that binary runs correct tests for the given filter and shard. Runs all shards of gtest_filter_unittest_ with the given filter, and verifies that the right set of tests were run. The union of tests run on each shard should be identical to tests_to_run, without duplicates. Args: gtest_filter: A filter to apply to the tests. total_shards: A total number of shards to split test run into. tests_to_run: A set of tests expected to run. args : Arguments to pass to the to the test binary. check_exit_0: When set to a true value, make sure that all shards return 0. """ tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # Windows removes empty variables from the environment when passing it # to a new process. This means it is impossible to pass an empty filter # into a process using the environment variable. However, we can still # test the case when the variable is not supplied (i.e., gtest_filter is # None). # pylint: disable-msg=C6403 if CAN_TEST_EMPTY_FILTER or gtest_filter != '': SetEnvVar(FILTER_ENV_VAR, gtest_filter) partition = [] for i in range(0, total_shards): (tests_run, exit_code) = RunWithSharding(total_shards, i, args) if check_exit_0: self.assertEqual(0, exit_code) partition.append(tests_run) self.AssertPartitionIsValid(tests_to_run, partition) SetEnvVar(FILTER_ENV_VAR, None) # pylint: enable-msg=C6403 def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run): """Checks that the binary runs correct set of tests for the given filter. Runs gtest_filter_unittest_ with the given filter, and enables disabled tests. Verifies that the right set of tests were run. Args: gtest_filter: A filter to apply to the tests. tests_to_run: A set of tests expected to run. """ tests_to_run = self.AdjustForParameterizedTests(tests_to_run) # Construct the command line. args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG] if gtest_filter is not None: args.append('--%s=%s' % (FILTER_FLAG, gtest_filter)) tests_run = RunAndExtractTestList(args)[0] self.AssertSetEqual(tests_run, tests_to_run) def setUp(self): """Sets up test case. Determines whether value-parameterized tests are enabled in the binary and sets the flags accordingly. """ global param_tests_present if param_tests_present is None: param_tests_present = PARAM_TEST_REGEX.search( RunAndReturnOutput()) is not None def testDefaultBehavior(self): """Tests the behavior of not specifying the filter.""" self.RunAndVerify(None, ACTIVE_TESTS) def testDefaultBehaviorWithShards(self): """Tests the behavior without the filter, with sharding enabled.""" self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS) self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS) def testEmptyFilter(self): """Tests an empty filter.""" self.RunAndVerify('', []) self.RunAndVerifyWithSharding('', 1, []) self.RunAndVerifyWithSharding('', 2, []) def testBadFilter(self): """Tests a filter that matches nothing.""" self.RunAndVerify('BadFilter', []) self.RunAndVerifyAllowingDisabled('BadFilter', []) def testFullName(self): """Tests filtering by full name.""" self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz']) self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz']) self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz']) def testUniversalFilters(self): """Tests filters that match everything.""" self.RunAndVerify('*', ACTIVE_TESTS) self.RunAndVerify('*.*', ACTIVE_TESTS) self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS) self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS) self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS) def testFilterByTestCase(self): """Tests filtering by test case name.""" self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz']) BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB'] self.RunAndVerify('BazTest.*', BAZ_TESTS) self.RunAndVerifyAllowingDisabled('BazTest.*', BAZ_TESTS + ['BazTest.DISABLED_TestC']) def testFilterByTest(self): """Tests filtering by test name.""" self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne']) def testFilterDisabledTests(self): """Select only the disabled tests to run.""" self.RunAndVerify('DISABLED_FoobarTest.Test1', []) self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1', ['DISABLED_FoobarTest.Test1']) self.RunAndVerify('*DISABLED_*', []) self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS) self.RunAndVerify('*.DISABLED_*', []) self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [ 'BarTest.DISABLED_TestFour', 'BarTest.DISABLED_TestFive', 'BazTest.DISABLED_TestC', 'DISABLED_FoobarTest.DISABLED_Test2', ]) self.RunAndVerify('DISABLED_*', []) self.RunAndVerifyAllowingDisabled('DISABLED_*', [ 'DISABLED_FoobarTest.Test1', 'DISABLED_FoobarTest.DISABLED_Test2', 'DISABLED_FoobarbazTest.TestA', ]) def testWildcardInTestCaseName(self): """Tests using wildcard in the test case name.""" self.RunAndVerify('*a*.*', [ 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) def testWildcardInTestName(self): """Tests using wildcard in the test name.""" self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA']) def testFilterWithoutDot(self): """Tests a filter that has no '.' in it.""" self.RunAndVerify('*z*', [ 'FooTest.Xyz', 'BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB', ]) def testTwoPatterns(self): """Tests filters that consist of two patterns.""" self.RunAndVerify('Foo*.*:*A*', [ 'FooTest.Abc', 'FooTest.Xyz', 'BazTest.TestA', ]) # An empty pattern + a non-empty one self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA']) def testThreePatterns(self): """Tests filters that consist of three patterns.""" self.RunAndVerify('*oo*:*A*:*One', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BazTest.TestOne', 'BazTest.TestA', ]) # The 2nd pattern is empty. self.RunAndVerify('*oo*::*One', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BazTest.TestOne', ]) # The last 2 patterns are empty. self.RunAndVerify('*oo*::', [ 'FooTest.Abc', 'FooTest.Xyz', ]) def testNegativeFilters(self): self.RunAndVerify('*-BazTest.TestOne', [ 'FooTest.Abc', 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', 'BazTest.TestA', 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) self.RunAndVerify('*-FooTest.Abc:BazTest.*', [ 'FooTest.Xyz', 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', ] + DEATH_TESTS + PARAM_TESTS) self.RunAndVerify('BarTest.*-BarTest.TestOne', [ 'BarTest.TestTwo', 'BarTest.TestThree', ]) # Tests without leading '*'. self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [ 'BarTest.TestOne', 'BarTest.TestTwo', 'BarTest.TestThree', ] + DEATH_TESTS + PARAM_TESTS) # Value parameterized tests. self.RunAndVerify('*/*', PARAM_TESTS) # Value parameterized tests filtering by the sequence name. self.RunAndVerify('SeqP/*', [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', ]) # Value parameterized tests filtering by the test name. self.RunAndVerify('*/0', [ 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestY/0', 'SeqQ/ParamTest.TestX/0', 'SeqQ/ParamTest.TestY/0', ]) def testFlagOverridesEnvVar(self): """Tests that the filter flag overrides the filtering env. variable.""" SetEnvVar(FILTER_ENV_VAR, 'Foo*') args = ['--%s=%s' % (FILTER_FLAG, '*One')] tests_run = RunAndExtractTestList(args)[0] SetEnvVar(FILTER_ENV_VAR, None) self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne']) def testShardStatusFileIsCreated(self): """Tests that the shard file is created if specified in the environment.""" shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), 'shard_status_file') self.assert_(not os.path.exists(shard_status_file)) extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} try: InvokeWithModifiedEnv(extra_env, RunAndReturnOutput) finally: self.assert_(os.path.exists(shard_status_file)) os.remove(shard_status_file) def testShardStatusFileIsCreatedWithListTests(self): """Tests that the shard file is created with the "list_tests" flag.""" shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), 'shard_status_file2') self.assert_(not os.path.exists(shard_status_file)) extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} try: output = InvokeWithModifiedEnv(extra_env, RunAndReturnOutput, [LIST_TESTS_FLAG]) finally: # This assertion ensures that Google Test enumerated the tests as # opposed to running them. self.assert_('[==========]' not in output, 'Unexpected output during test enumeration.\n' 'Please ensure that LIST_TESTS_FLAG is assigned the\n' 'correct flag value for listing Google Test tests.') self.assert_(os.path.exists(shard_status_file)) os.remove(shard_status_file) if SUPPORTS_DEATH_TESTS: def testShardingWorksWithDeathTests(self): """Tests integration with death tests and sharding.""" gtest_filter = 'HasDeathTest.*:SeqP/*' expected_tests = [ 'HasDeathTest.Test1', 'HasDeathTest.Test2', 'SeqP/ParamTest.TestX/0', 'SeqP/ParamTest.TestX/1', 'SeqP/ParamTest.TestY/0', 'SeqP/ParamTest.TestY/1', ] for flag in ['--gtest_death_test_style=threadsafe', '--gtest_death_test_style=fast']: self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests, check_exit_0=True, args=[flag]) self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests, check_exit_0=True, args=[flag]) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_filter_unittest_.cc000066400000000000000000000067541273231111400311620ustar00rootroot00000000000000// 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) // Unit test for Google Test test filters. // // A user can specify which test(s) in a Google Test program to run via // either the GTEST_FILTER environment variable or the --gtest_filter // flag. This is used for testing such functionality. // // The program will be invoked from a Python unit test. Don't run it // directly. #include "gtest/gtest.h" namespace { // Test case FooTest. class FooTest : public testing::Test { }; TEST_F(FooTest, Abc) { } TEST_F(FooTest, Xyz) { FAIL() << "Expected failure."; } // Test case BarTest. TEST(BarTest, TestOne) { } TEST(BarTest, TestTwo) { } TEST(BarTest, TestThree) { } TEST(BarTest, DISABLED_TestFour) { FAIL() << "Expected failure."; } TEST(BarTest, DISABLED_TestFive) { FAIL() << "Expected failure."; } // Test case BazTest. TEST(BazTest, TestOne) { FAIL() << "Expected failure."; } TEST(BazTest, TestA) { } TEST(BazTest, TestB) { } TEST(BazTest, DISABLED_TestC) { FAIL() << "Expected failure."; } // Test case HasDeathTest TEST(HasDeathTest, Test1) { EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // We need at least two death tests to make sure that the all death tests // aren't on the first shard. TEST(HasDeathTest, Test2) { EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); } // Test case FoobarTest TEST(DISABLED_FoobarTest, Test1) { FAIL() << "Expected failure."; } TEST(DISABLED_FoobarTest, DISABLED_Test2) { FAIL() << "Expected failure."; } // Test case FoobarbazTest TEST(DISABLED_FoobarbazTest, TestA) { FAIL() << "Expected failure."; } #if GTEST_HAS_PARAM_TEST class ParamTest : public testing::TestWithParam { }; TEST_P(ParamTest, TestX) { } TEST_P(ParamTest, TestY) { } INSTANTIATE_TEST_CASE_P(SeqP, ParamTest, testing::Values(1, 2)); INSTANTIATE_TEST_CASE_P(SeqQ, ParamTest, testing::Values(5, 6)); #endif // GTEST_HAS_PARAM_TEST } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_help_test.py000077500000000000000000000133401273231111400276210ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2009, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Tests the --help flag of Google C++ Testing Framework. SYNOPSIS gtest_help_test.py --build_dir=BUILD/DIR # where BUILD/DIR contains the built gtest_help_test_ file. gtest_help_test.py """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import gtest_test_utils IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' IS_WINDOWS = os.name == 'nt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') FLAG_PREFIX = '--gtest_' DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to' UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG), re.sub('^--', '/', LIST_TESTS_FLAG), re.sub('_', '-', LIST_TESTS_FLAG)] INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing' SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess( [PROGRAM_PATH, LIST_TESTS_FLAG]).output # The help message must match this regex. HELP_REGEX = re.compile( FLAG_PREFIX + r'list_tests.*' + FLAG_PREFIX + r'filter=.*' + FLAG_PREFIX + r'also_run_disabled_tests.*' + FLAG_PREFIX + r'repeat=.*' + FLAG_PREFIX + r'shuffle.*' + FLAG_PREFIX + r'random_seed=.*' + FLAG_PREFIX + r'color=.*' + FLAG_PREFIX + r'print_time.*' + FLAG_PREFIX + r'output=.*' + FLAG_PREFIX + r'break_on_failure.*' + FLAG_PREFIX + r'throw_on_failure.*' + FLAG_PREFIX + r'catch_exceptions=0.*', re.DOTALL) def RunWithFlag(flag): """Runs gtest_help_test_ with the given flag. Returns: the exit code and the text output as a tuple. Args: flag: the command-line flag to pass to gtest_help_test_, or None. """ if flag is None: command = [PROGRAM_PATH] else: command = [PROGRAM_PATH, flag] child = gtest_test_utils.Subprocess(command) return child.exit_code, child.output class GTestHelpTest(gtest_test_utils.TestCase): """Tests the --help flag and its equivalent forms.""" def TestHelpFlag(self, flag): """Verifies correct behavior when help flag is specified. The right message must be printed and the tests must skipped when the given flag is specified. Args: flag: A flag to pass to the binary or None. """ exit_code, output = RunWithFlag(flag) self.assertEquals(0, exit_code) self.assert_(HELP_REGEX.search(output), output) if IS_LINUX: self.assert_(STREAM_RESULT_TO_FLAG in output, output) else: self.assert_(STREAM_RESULT_TO_FLAG not in output, output) if SUPPORTS_DEATH_TESTS and not IS_WINDOWS: self.assert_(DEATH_TEST_STYLE_FLAG in output, output) else: self.assert_(DEATH_TEST_STYLE_FLAG not in output, output) def TestNonHelpFlag(self, flag): """Verifies correct behavior when no help flag is specified. Verifies that when no help flag is specified, the tests are run and the help message is not printed. Args: flag: A flag to pass to the binary or None. """ exit_code, output = RunWithFlag(flag) self.assert_(exit_code != 0) self.assert_(not HELP_REGEX.search(output), output) def testPrintsHelpWithFullFlag(self): self.TestHelpFlag('--help') def testPrintsHelpWithShortFlag(self): self.TestHelpFlag('-h') def testPrintsHelpWithQuestionFlag(self): self.TestHelpFlag('-?') def testPrintsHelpWithWindowsStyleQuestionFlag(self): self.TestHelpFlag('/?') def testPrintsHelpWithUnrecognizedGoogleTestFlag(self): self.TestHelpFlag(UNKNOWN_FLAG) def testPrintsHelpWithIncorrectFlagStyle(self): for incorrect_flag in INCORRECT_FLAG_VARIANTS: self.TestHelpFlag(incorrect_flag) def testRunsTestsWithoutHelpFlag(self): """Verifies that when no help flag is specified, the tests are run and the help message is not printed.""" self.TestNonHelpFlag(None) def testRunsTestsWithGtestInternalFlag(self): """Verifies that the tests are run and no help message is printed when a flag starting with Google Test prefix and 'internal_' is supplied.""" self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_help_test_.cc000066400000000000000000000041231273231111400277110ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // This program is meant to be run by gtest_help_test.py. Do not run // it directly. #include "gtest/gtest.h" // When a help flag is specified, this program should skip the tests // and exit with 0; otherwise the following test will be executed, // causing this program to exit with a non-zero code. TEST(HelpFlagTest, ShouldNotBeRun) { ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; } #if GTEST_HAS_DEATH_TEST TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {} #endif mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_list_tests_unittest.py000077500000000000000000000145631273231111400317760ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test for Google Test's --gtest_list_tests flag. A user can ask Google Test to list all tests by specifying the --gtest_list_tests flag. This script tests such functionality by invoking gtest_list_tests_unittest_ (a program written with Google Test) the command line flags. """ __author__ = 'phanna@google.com (Patrick Hanna)' import gtest_test_utils import re # Constants. # The command line flag for enabling/disabling listing all tests. LIST_TESTS_FLAG = 'gtest_list_tests' # Path to the gtest_list_tests_unittest_ program. EXE_PATH = gtest_test_utils.GetTestExecutablePath('gtest_list_tests_unittest_') # The expected output when running gtest_list_tests_unittest_ with # --gtest_list_tests EXPECTED_OUTPUT_NO_FILTER_RE = re.compile(r"""FooDeathTest\. Test1 Foo\. Bar1 Bar2 DISABLED_Bar3 Abc\. Xyz Def FooBar\. Baz FooTest\. Test1 DISABLED_Test2 Test3 TypedTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. TestA TestB TypedTest/1\. # TypeParam = int\s*\* TestA TestB TypedTest/2\. # TypeParam = .*MyArray TestA TestB My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. TestA TestB My/TypeParamTest/1\. # TypeParam = int\s*\* TestA TestB My/TypeParamTest/2\. # TypeParam = .*MyArray TestA TestB MyInstantiation/ValueParamTest\. TestA/0 # GetParam\(\) = one line TestA/1 # GetParam\(\) = two\\nlines TestA/2 # GetParam\(\) = a very\\nlo{241}\.\.\. TestB/0 # GetParam\(\) = one line TestB/1 # GetParam\(\) = two\\nlines TestB/2 # GetParam\(\) = a very\\nlo{241}\.\.\. """) # The expected output when running gtest_list_tests_unittest_ with # --gtest_list_tests and --gtest_filter=Foo*. EXPECTED_OUTPUT_FILTER_FOO_RE = re.compile(r"""FooDeathTest\. Test1 Foo\. Bar1 Bar2 DISABLED_Bar3 FooBar\. Baz FooTest\. Test1 DISABLED_Test2 Test3 """) # Utilities. def Run(args): """Runs gtest_list_tests_unittest_ and returns the list of tests printed.""" return gtest_test_utils.Subprocess([EXE_PATH] + args, capture_stderr=False).output # The unit test. class GTestListTestsUnitTest(gtest_test_utils.TestCase): """Tests using the --gtest_list_tests flag to list all tests.""" def RunAndVerify(self, flag_value, expected_output_re, other_flag): """Runs gtest_list_tests_unittest_ and verifies that it prints the correct tests. Args: flag_value: value of the --gtest_list_tests flag; None if the flag should not be present. expected_output_re: regular expression that matches the expected output after running command; other_flag: a different flag to be passed to command along with gtest_list_tests; None if the flag should not be present. """ if flag_value is None: flag = '' flag_expression = 'not set' elif flag_value == '0': flag = '--%s=0' % LIST_TESTS_FLAG flag_expression = '0' else: flag = '--%s' % LIST_TESTS_FLAG flag_expression = '1' args = [flag] if other_flag is not None: args += [other_flag] output = Run(args) if expected_output_re: self.assert_( expected_output_re.match(output), ('when %s is %s, the output of "%s" is "%s",\n' 'which does not match regex "%s"' % (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output, expected_output_re.pattern))) else: self.assert_( not EXPECTED_OUTPUT_NO_FILTER_RE.match(output), ('when %s is %s, the output of "%s" is "%s"'% (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output))) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(flag_value=None, expected_output_re=None, other_flag=None) def testFlag(self): """Tests using the --gtest_list_tests flag.""" self.RunAndVerify(flag_value='0', expected_output_re=None, other_flag=None) self.RunAndVerify(flag_value='1', expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, other_flag=None) def testOverrideNonFilterFlags(self): """Tests that --gtest_list_tests overrides the non-filter flags.""" self.RunAndVerify(flag_value='1', expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, other_flag='--gtest_break_on_failure') def testWithFilterFlags(self): """Tests that --gtest_list_tests takes into account the --gtest_filter flag.""" self.RunAndVerify(flag_value='1', expected_output_re=EXPECTED_OUTPUT_FILTER_FOO_RE, other_flag='--gtest_filter=Foo*') if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_list_tests_unittest_.cc000066400000000000000000000111461273231111400320610ustar00rootroot00000000000000// 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: phanna@google.com (Patrick Hanna) // Unit test for Google Test's --gtest_list_tests flag. // // A user can ask Google Test to list all tests that will run // so that when using a filter, a user will know what // tests to look for. The tests will not be run after listing. // // This program will be invoked from a Python unit test. // Don't run it directly. #include "gtest/gtest.h" // Several different test cases and tests that will be listed. TEST(Foo, Bar1) { } TEST(Foo, Bar2) { } TEST(Foo, DISABLED_Bar3) { } TEST(Abc, Xyz) { } TEST(Abc, Def) { } TEST(FooBar, Baz) { } class FooTest : public testing::Test { }; TEST_F(FooTest, Test1) { } TEST_F(FooTest, DISABLED_Test2) { } TEST_F(FooTest, Test3) { } TEST(FooDeathTest, Test1) { } // A group of value-parameterized tests. class MyType { public: explicit MyType(const std::string& a_value) : value_(a_value) {} const std::string& value() const { return value_; } private: std::string value_; }; // Teaches Google Test how to print a MyType. void PrintTo(const MyType& x, std::ostream* os) { *os << x.value(); } class ValueParamTest : public testing::TestWithParam { }; TEST_P(ValueParamTest, TestA) { } TEST_P(ValueParamTest, TestB) { } INSTANTIATE_TEST_CASE_P( MyInstantiation, ValueParamTest, testing::Values(MyType("one line"), MyType("two\nlines"), MyType("a very\nloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"))); // NOLINT // A group of typed tests. // A deliberately long type name for testing the line-truncating // behavior when printing a type parameter. class VeryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName { // NOLINT }; template class TypedTest : public testing::Test { }; template class MyArray { }; typedef testing::Types > MyTypes; TYPED_TEST_CASE(TypedTest, MyTypes); TYPED_TEST(TypedTest, TestA) { } TYPED_TEST(TypedTest, TestB) { } // A group of type-parameterized tests. template class TypeParamTest : public testing::Test { }; TYPED_TEST_CASE_P(TypeParamTest); TYPED_TEST_P(TypeParamTest, TestA) { } TYPED_TEST_P(TypeParamTest, TestB) { } REGISTER_TYPED_TEST_CASE_P(TypeParamTest, TestA, TestB); INSTANTIATE_TYPED_TEST_CASE_P(My, TypeParamTest, MyTypes); int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_main_unittest.cc000066400000000000000000000035401273231111400304500ustar00rootroot00000000000000// 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) #include "gtest/gtest.h" // Tests that we don't have to define main() when we link to // gtest_main instead of gtest. namespace { TEST(GTestMainTest, ShouldSucceed) { } } // namespace // We are using the main() function defined in src/gtest_main.cc, so // we don't define it here. mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_no_test_unittest.cc000066400000000000000000000046171273231111400312050ustar00rootroot00000000000000// 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. // Tests that a Google Test program that has no test defined can run // successfully. // // Author: wan@google.com (Zhanyong Wan) #include "gtest/gtest.h" int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); // An ad-hoc assertion outside of all tests. // // This serves three purposes: // // 1. It verifies that an ad-hoc assertion can be executed even if // no test is defined. // 2. It verifies that a failed ad-hoc assertion causes the test // program to fail. // 3. We had a bug where the XML output won't be generated if an // assertion is executed before RUN_ALL_TESTS() is called, even // though --gtest_output=xml is specified. This makes sure the // bug is fixed and doesn't regress. EXPECT_EQ(1, 2); // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero. return RUN_ALL_TESTS() ? 0 : 1; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_output_test.py000077500000000000000000000273451273231111400302430ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Tests the text output of Google C++ Testing Framework. SYNOPSIS gtest_output_test.py --build_dir=BUILD/DIR --gengolden # where BUILD/DIR contains the built gtest_output_test_ file. gtest_output_test.py --gengolden gtest_output_test.py """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys import gtest_test_utils # The flag for generating the golden file GENGOLDEN_FLAG = '--gengolden' CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS' IS_WINDOWS = os.name == 'nt' # TODO(vladl@google.com): remove the _lin suffix. GOLDEN_NAME = 'gtest_output_test_golden_lin.txt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_') # At least one command we exercise must not have the # --gtest_internal_skip_environment_and_ad_hoc_tests flag. COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, '--gtest_print_time', '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) COMMAND_WITH_DISABLED = ( {}, [PROGRAM_PATH, '--gtest_also_run_disabled_tests', '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=*DISABLED_*']) COMMAND_WITH_SHARDING = ( {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, [PROGRAM_PATH, '--gtest_internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=PassingTest.*']) GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) def ToUnixLineEnding(s): """Changes all Windows/Mac line endings in s to UNIX line endings.""" return s.replace('\r\n', '\n').replace('\r', '\n') def RemoveLocations(test_output): """Removes all file location info from a Google Test program's output. Args: test_output: the output of a Google Test program. Returns: output with all file location info (in the form of 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by 'FILE_NAME:#: '. """ return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output) def RemoveStackTraceDetails(output): """Removes all stack traces from a Google Test program's output.""" # *? means "find the shortest string that matches". return re.sub(r'Stack trace:(.|\n)*?\n\n', 'Stack trace: (omitted)\n\n', output) def RemoveStackTraces(output): """Removes all traces of stack traces from a Google Test program's output.""" # *? means "find the shortest string that matches". return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output) def RemoveTime(output): """Removes all time information from a Google Test program's output.""" return re.sub(r'\(\d+ ms', '(? ms', output) def RemoveTypeInfoDetails(test_output): """Removes compiler-specific type info from Google Test program's output. Args: test_output: the output of a Google Test program. Returns: output with type information normalized to canonical form. """ # some compilers output the name of type 'unsigned int' as 'unsigned' return re.sub(r'unsigned int', 'unsigned', test_output) def NormalizeToCurrentPlatform(test_output): """Normalizes platform specific output details for easier comparison.""" if IS_WINDOWS: # Removes the color information that is not present on Windows. test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output) # Changes failure message headers into the Windows format. test_output = re.sub(r': Failure\n', r': error: ', test_output) # Changes file(line_number) to file:line_number. test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output) return test_output def RemoveTestCounts(output): """Removes test counts from a Google Test program's output.""" output = re.sub(r'\d+ tests?, listed below', '? tests, listed below', output) output = re.sub(r'\d+ FAILED TESTS', '? FAILED TESTS', output) output = re.sub(r'\d+ tests? from \d+ test cases?', '? tests from ? test cases', output) output = re.sub(r'\d+ tests? from ([a-zA-Z_])', r'? tests from \1', output) return re.sub(r'\d+ tests?\.', '? tests.', output) def RemoveMatchingTests(test_output, pattern): """Removes output of specified tests from a Google Test program's output. This function strips not only the beginning and the end of a test but also all output in between. Args: test_output: A string containing the test output. pattern: A regex string that matches names of test cases or tests to remove. Returns: Contents of test_output with tests whose names match pattern removed. """ test_output = re.sub( r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % ( pattern, pattern), '', test_output) return re.sub(r'.*%s.*\n' % pattern, '', test_output) def NormalizeOutput(output): """Normalizes output (the output of gtest_output_test_.exe).""" output = ToUnixLineEnding(output) output = RemoveLocations(output) output = RemoveStackTraceDetails(output) output = RemoveTime(output) return output def GetShellCommandOutput(env_cmd): """Runs a command in a sub-process, and returns its output in a string. Args: env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra environment variables to set, and element 1 is a string with the command and any flags. Returns: A string with the command's combined standard and diagnostic output. """ # Spawns cmd in a sub-process, and gets its standard I/O file objects. # Set and save the environment properly. environ = os.environ.copy() environ.update(env_cmd[0]) p = gtest_test_utils.Subprocess(env_cmd[1], env=environ) return p.output def GetCommandOutput(env_cmd): """Runs a command and returns its output with all file location info stripped off. Args: env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra environment variables to set, and element 1 is a string with the command and any flags. """ # Disables exception pop-ups on Windows. environ, cmdline = env_cmd environ = dict(environ) # Ensures we are modifying a copy. environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1' return NormalizeOutput(GetShellCommandOutput((environ, cmdline))) def GetOutputOfAllCommands(): """Returns concatenated output from several representative commands.""" return (GetCommandOutput(COMMAND_WITH_COLOR) + GetCommandOutput(COMMAND_WITH_TIME) + GetCommandOutput(COMMAND_WITH_DISABLED) + GetCommandOutput(COMMAND_WITH_SHARDING)) test_list = GetShellCommandOutput(COMMAND_LIST_TESTS) SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list SUPPORTS_STACK_TRACES = False CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS and SUPPORTS_THREADS) class GTestOutputTest(gtest_test_utils.TestCase): def RemoveUnsupportedTests(self, test_output): if not SUPPORTS_DEATH_TESTS: test_output = RemoveMatchingTests(test_output, 'DeathTest') if not SUPPORTS_TYPED_TESTS: test_output = RemoveMatchingTests(test_output, 'TypedTest') test_output = RemoveMatchingTests(test_output, 'TypedDeathTest') test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest') if not SUPPORTS_THREADS: test_output = RemoveMatchingTests(test_output, 'ExpectFailureWithThreadsTest') test_output = RemoveMatchingTests(test_output, 'ScopedFakeTestPartResultReporterTest') test_output = RemoveMatchingTests(test_output, 'WorksConcurrently') if not SUPPORTS_STACK_TRACES: test_output = RemoveStackTraces(test_output) return test_output def testOutput(self): output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'rb') # A mis-configured source control system can cause \r appear in EOL # sequences when we read the golden file irrespective of an operating # system used. Therefore, we need to strip those \r's from newlines # unconditionally. golden = ToUnixLineEnding(golden_file.read()) golden_file.close() # We want the test to pass regardless of certain features being # supported or not. # We still have to remove type name specifics in all cases. normalized_actual = RemoveTypeInfoDetails(output) normalized_golden = RemoveTypeInfoDetails(golden) if CAN_GENERATE_GOLDEN_FILE: self.assertEqual(normalized_golden, normalized_actual) else: normalized_actual = NormalizeToCurrentPlatform( RemoveTestCounts(normalized_actual)) normalized_golden = NormalizeToCurrentPlatform( RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden))) # This code is very handy when debugging golden file differences: if os.getenv('DEBUG_GTEST_OUTPUT_TEST'): open(os.path.join( gtest_test_utils.GetSourceDir(), '_gtest_output_test_normalized_actual.txt'), 'wb').write( normalized_actual) open(os.path.join( gtest_test_utils.GetSourceDir(), '_gtest_output_test_normalized_golden.txt'), 'wb').write( normalized_golden) self.assertEqual(normalized_golden, normalized_actual) if __name__ == '__main__': if sys.argv[1:] == [GENGOLDEN_FLAG]: if CAN_GENERATE_GOLDEN_FILE: output = GetOutputOfAllCommands() golden_file = open(GOLDEN_PATH, 'wb') golden_file.write(output) golden_file.close() else: message = ( """Unable to write a golden file when compiled in an environment that does not support all the required features (death tests, typed tests, and multiple threads). Please generate the golden file using a binary built with those features enabled.""") sys.stderr.write(message) sys.exit(1) else: gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_output_test_.cc000066400000000000000000000772661273231111400303430ustar00rootroot00000000000000// 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. // // The purpose of this file is to generate Google Test output under // various conditions. The output will then be verified by // gtest_output_test.py to ensure that Google Test generates the // desired messages. Therefore, most tests in this file are MEANT TO // FAIL. // // Author: wan@google.com (Zhanyong Wan) #include "gtest/gtest-spi.h" #include "gtest/gtest.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_ #include #if GTEST_IS_THREADSAFE using testing::ScopedFakeTestPartResultReporter; using testing::TestPartResultArray; using testing::internal::Notification; using testing::internal::ThreadWithParam; #endif namespace posix = ::testing::internal::posix; using testing::internal::scoped_ptr; // Tests catching fatal failures. // A subroutine used by the following test. void TestEq1(int x) { ASSERT_EQ(1, x); } // This function calls a test subroutine, catches the fatal failure it // generates, and then returns early. void TryTestSubroutine() { // Calls a subrountine that yields a fatal failure. TestEq1(2); // Catches the fatal failure and aborts the test. // // The testing::Test:: prefix is necessary when calling // HasFatalFailure() outside of a TEST, TEST_F, or test fixture. if (testing::Test::HasFatalFailure()) return; // If we get here, something is wrong. FAIL() << "This should never be reached."; } TEST(PassingTest, PassingTest1) { } TEST(PassingTest, PassingTest2) { } // Tests that parameters of failing parameterized tests are printed in the // failing test summary. class FailingParamTest : public testing::TestWithParam {}; TEST_P(FailingParamTest, Fails) { EXPECT_EQ(1, GetParam()); } // This generates a test which will fail. Google Test is expected to print // its parameter when it outputs the list of all failed tests. INSTANTIATE_TEST_CASE_P(PrintingFailingParams, FailingParamTest, testing::Values(2)); static const char kGoldenString[] = "\"Line\0 1\"\nLine 2"; TEST(NonfatalFailureTest, EscapesStringOperands) { std::string actual = "actual \"string\""; EXPECT_EQ(kGoldenString, actual); const char* golden = kGoldenString; EXPECT_EQ(golden, actual); } // Tests catching a fatal failure in a subroutine. TEST(FatalFailureTest, FatalFailureInSubroutine) { printf("(expecting a failure that x should be 1)\n"); TryTestSubroutine(); } // Tests catching a fatal failure in a nested subroutine. TEST(FatalFailureTest, FatalFailureInNestedSubroutine) { printf("(expecting a failure that x should be 1)\n"); // Calls a subrountine that yields a fatal failure. TryTestSubroutine(); // Catches the fatal failure and aborts the test. // // When calling HasFatalFailure() inside a TEST, TEST_F, or test // fixture, the testing::Test:: prefix is not needed. if (HasFatalFailure()) return; // If we get here, something is wrong. FAIL() << "This should never be reached."; } // Tests HasFatalFailure() after a failed EXPECT check. TEST(FatalFailureTest, NonfatalFailureInSubroutine) { printf("(expecting a failure on false)\n"); EXPECT_TRUE(false); // Generates a nonfatal failure ASSERT_FALSE(HasFatalFailure()); // This should succeed. } // Tests interleaving user logging and Google Test assertions. TEST(LoggingTest, InterleavingLoggingAndAssertions) { static const int a[4] = { 3, 9, 2, 6 }; printf("(expecting 2 failures on (3) >= (a[i]))\n"); for (int i = 0; i < static_cast(sizeof(a)/sizeof(*a)); i++) { printf("i == %d\n", i); EXPECT_GE(3, a[i]); } } // Tests the SCOPED_TRACE macro. // A helper function for testing SCOPED_TRACE. void SubWithoutTrace(int n) { EXPECT_EQ(1, n); ASSERT_EQ(2, n); } // Another helper function for testing SCOPED_TRACE. void SubWithTrace(int n) { SCOPED_TRACE(testing::Message() << "n = " << n); SubWithoutTrace(n); } // Tests that SCOPED_TRACE() obeys lexical scopes. TEST(SCOPED_TRACETest, ObeysScopes) { printf("(expected to fail)\n"); // There should be no trace before SCOPED_TRACE() is invoked. ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; { SCOPED_TRACE("Expected trace"); // After SCOPED_TRACE(), a failure in the current scope should contain // the trace. ADD_FAILURE() << "This failure is expected, and should have a trace."; } // Once the control leaves the scope of the SCOPED_TRACE(), there // should be no trace again. ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; } // Tests that SCOPED_TRACE works inside a loop. TEST(SCOPED_TRACETest, WorksInLoop) { printf("(expected to fail)\n"); for (int i = 1; i <= 2; i++) { SCOPED_TRACE(testing::Message() << "i = " << i); SubWithoutTrace(i); } } // Tests that SCOPED_TRACE works in a subroutine. TEST(SCOPED_TRACETest, WorksInSubroutine) { printf("(expected to fail)\n"); SubWithTrace(1); SubWithTrace(2); } // Tests that SCOPED_TRACE can be nested. TEST(SCOPED_TRACETest, CanBeNested) { printf("(expected to fail)\n"); SCOPED_TRACE(""); // A trace without a message. SubWithTrace(2); } // Tests that multiple SCOPED_TRACEs can be used in the same scope. TEST(SCOPED_TRACETest, CanBeRepeated) { printf("(expected to fail)\n"); SCOPED_TRACE("A"); ADD_FAILURE() << "This failure is expected, and should contain trace point A."; SCOPED_TRACE("B"); ADD_FAILURE() << "This failure is expected, and should contain trace point A and B."; { SCOPED_TRACE("C"); ADD_FAILURE() << "This failure is expected, and should " << "contain trace point A, B, and C."; } SCOPED_TRACE("D"); ADD_FAILURE() << "This failure is expected, and should " << "contain trace point A, B, and D."; } #if GTEST_IS_THREADSAFE // Tests that SCOPED_TRACE()s can be used concurrently from multiple // threads. Namely, an assertion should be affected by // SCOPED_TRACE()s in its own thread only. // Here's the sequence of actions that happen in the test: // // Thread A (main) | Thread B (spawned) // ===============================|================================ // spawns thread B | // -------------------------------+-------------------------------- // waits for n1 | SCOPED_TRACE("Trace B"); // | generates failure #1 // | notifies n1 // -------------------------------+-------------------------------- // SCOPED_TRACE("Trace A"); | waits for n2 // generates failure #2 | // notifies n2 | // -------------------------------|-------------------------------- // waits for n3 | generates failure #3 // | trace B dies // | generates failure #4 // | notifies n3 // -------------------------------|-------------------------------- // generates failure #5 | finishes // trace A dies | // generates failure #6 | // -------------------------------|-------------------------------- // waits for thread B to finish | struct CheckPoints { Notification n1; Notification n2; Notification n3; }; static void ThreadWithScopedTrace(CheckPoints* check_points) { { SCOPED_TRACE("Trace B"); ADD_FAILURE() << "Expected failure #1 (in thread B, only trace B alive)."; check_points->n1.Notify(); check_points->n2.WaitForNotification(); ADD_FAILURE() << "Expected failure #3 (in thread B, trace A & B both alive)."; } // Trace B dies here. ADD_FAILURE() << "Expected failure #4 (in thread B, only trace A alive)."; check_points->n3.Notify(); } TEST(SCOPED_TRACETest, WorksConcurrently) { printf("(expecting 6 failures)\n"); CheckPoints check_points; ThreadWithParam thread(&ThreadWithScopedTrace, &check_points, NULL); check_points.n1.WaitForNotification(); { SCOPED_TRACE("Trace A"); ADD_FAILURE() << "Expected failure #2 (in thread A, trace A & B both alive)."; check_points.n2.Notify(); check_points.n3.WaitForNotification(); ADD_FAILURE() << "Expected failure #5 (in thread A, only trace A alive)."; } // Trace A dies here. ADD_FAILURE() << "Expected failure #6 (in thread A, no trace alive)."; thread.Join(); } #endif // GTEST_IS_THREADSAFE TEST(DisabledTestsWarningTest, DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { // This test body is intentionally empty. Its sole purpose is for // verifying that the --gtest_also_run_disabled_tests flag // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of // the test output. } // Tests using assertions outside of TEST and TEST_F. // // This function creates two failures intentionally. void AdHocTest() { printf("The non-test part of the code is expected to have 2 failures.\n\n"); EXPECT_TRUE(false); EXPECT_EQ(2, 3); } // Runs all TESTs, all TEST_Fs, and the ad hoc test. int RunAllTests() { AdHocTest(); return RUN_ALL_TESTS(); } // Tests non-fatal failures in the fixture constructor. class NonFatalFailureInFixtureConstructorTest : public testing::Test { protected: NonFatalFailureInFixtureConstructorTest() { printf("(expecting 5 failures)\n"); ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor."; } ~NonFatalFailureInFixtureConstructorTest() { ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor."; } virtual void SetUp() { ADD_FAILURE() << "Expected failure #2, in SetUp()."; } virtual void TearDown() { ADD_FAILURE() << "Expected failure #4, in TearDown."; } }; TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor) { ADD_FAILURE() << "Expected failure #3, in the test body."; } // Tests fatal failures in the fixture constructor. class FatalFailureInFixtureConstructorTest : public testing::Test { protected: FatalFailureInFixtureConstructorTest() { printf("(expecting 2 failures)\n"); Init(); } ~FatalFailureInFixtureConstructorTest() { ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor."; } virtual void SetUp() { ADD_FAILURE() << "UNEXPECTED failure in SetUp(). " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } virtual void TearDown() { ADD_FAILURE() << "UNEXPECTED failure in TearDown(). " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } private: void Init() { FAIL() << "Expected failure #1, in the test fixture c'tor."; } }; TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor) { ADD_FAILURE() << "UNEXPECTED failure in the test body. " << "We should never get here, as the test fixture c'tor " << "had a fatal failure."; } // Tests non-fatal failures in SetUp(). class NonFatalFailureInSetUpTest : public testing::Test { protected: virtual ~NonFatalFailureInSetUpTest() { Deinit(); } virtual void SetUp() { printf("(expecting 4 failures)\n"); ADD_FAILURE() << "Expected failure #1, in SetUp()."; } virtual void TearDown() { FAIL() << "Expected failure #3, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #4, in the test fixture d'tor."; } }; TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp) { FAIL() << "Expected failure #2, in the test function."; } // Tests fatal failures in SetUp(). class FatalFailureInSetUpTest : public testing::Test { protected: virtual ~FatalFailureInSetUpTest() { Deinit(); } virtual void SetUp() { printf("(expecting 3 failures)\n"); FAIL() << "Expected failure #1, in SetUp()."; } virtual void TearDown() { FAIL() << "Expected failure #2, in TearDown()."; } private: void Deinit() { FAIL() << "Expected failure #3, in the test fixture d'tor."; } }; TEST_F(FatalFailureInSetUpTest, FailureInSetUp) { FAIL() << "UNEXPECTED failure in the test function. " << "We should never get here, as SetUp() failed."; } TEST(AddFailureAtTest, MessageContainsSpecifiedFileAndLineNumber) { ADD_FAILURE_AT("foo.cc", 42) << "Expected failure in foo.cc"; } #if GTEST_IS_THREADSAFE // A unary function that may die. void DieIf(bool should_die) { GTEST_CHECK_(!should_die) << " - death inside DieIf()."; } // Tests running death tests in a multi-threaded context. // Used for coordination between the main and the spawn thread. struct SpawnThreadNotifications { SpawnThreadNotifications() {} Notification spawn_thread_started; Notification spawn_thread_ok_to_terminate; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications); }; // The function to be executed in the thread spawn by the // MultipleThreads test (below). static void ThreadRoutine(SpawnThreadNotifications* notifications) { // Signals the main thread that this thread has started. notifications->spawn_thread_started.Notify(); // Waits for permission to finish from the main thread. notifications->spawn_thread_ok_to_terminate.WaitForNotification(); } // This is a death-test test, but it's not named with a DeathTest // suffix. It starts threads which might interfere with later // death tests, so it must run after all other death tests. class DeathTestAndMultiThreadsTest : public testing::Test { protected: // Starts a thread and waits for it to begin. virtual void SetUp() { thread_.reset(new ThreadWithParam( &ThreadRoutine, ¬ifications_, NULL)); notifications_.spawn_thread_started.WaitForNotification(); } // Tells the thread to finish, and reaps it. // Depending on the version of the thread library in use, // a manager thread might still be left running that will interfere // with later death tests. This is unfortunate, but this class // cleans up after itself as best it can. virtual void TearDown() { notifications_.spawn_thread_ok_to_terminate.Notify(); } private: SpawnThreadNotifications notifications_; scoped_ptr > thread_; }; #endif // GTEST_IS_THREADSAFE // The MixedUpTestCaseTest test case verifies that Google Test will fail a // test if it uses a different fixture class than what other tests in // the same test case use. It deliberately contains two fixture // classes with the same name but defined in different namespaces. // The MixedUpTestCaseWithSameTestNameTest test case verifies that // when the user defines two tests with the same test case name AND // same test name (but in different namespaces), the second test will // fail. namespace foo { class MixedUpTestCaseTest : public testing::Test { }; TEST_F(MixedUpTestCaseTest, FirstTestFromNamespaceFoo) {} TEST_F(MixedUpTestCaseTest, SecondTestFromNamespaceFoo) {} class MixedUpTestCaseWithSameTestNameTest : public testing::Test { }; TEST_F(MixedUpTestCaseWithSameTestNameTest, TheSecondTestWithThisNameShouldFail) {} } // namespace foo namespace bar { class MixedUpTestCaseTest : public testing::Test { }; // The following two tests are expected to fail. We rely on the // golden file to check that Google Test generates the right error message. TEST_F(MixedUpTestCaseTest, ThisShouldFail) {} TEST_F(MixedUpTestCaseTest, ThisShouldFailToo) {} class MixedUpTestCaseWithSameTestNameTest : public testing::Test { }; // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST_F(MixedUpTestCaseWithSameTestNameTest, TheSecondTestWithThisNameShouldFail) {} } // namespace bar // The following two test cases verify that Google Test catches the user // error of mixing TEST and TEST_F in the same test case. The first // test case checks the scenario where TEST_F appears before TEST, and // the second one checks where TEST appears before TEST_F. class TEST_F_before_TEST_in_same_test_case : public testing::Test { }; TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {} // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {} class TEST_before_TEST_F_in_same_test_case : public testing::Test { }; TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {} // Expected to fail. We rely on the golden file to check that Google Test // generates the right error message. TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail) { } // Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE(). int global_integer = 0; // Tests that EXPECT_NONFATAL_FAILURE() can reference global variables. TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables) { global_integer = 0; EXPECT_NONFATAL_FAILURE({ EXPECT_EQ(1, global_integer) << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() can reference local variables // (static or not). TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables) { int m = 0; static int n; n = 1; EXPECT_NONFATAL_FAILURE({ EXPECT_EQ(m, n) << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly // one non-fatal failure and no fatal failure. TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure) { EXPECT_NONFATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure."; }, "Expected non-fatal failure."); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there is no // non-fatal failure. TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there are two // non-fatal failures. TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure 1."; ADD_FAILURE() << "Expected non-fatal failure 2."; }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal // failure. TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ FAIL() << "Expected fatal failure."; }, ""); } // Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being // tested returns. TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns) { printf("(expecting a failure)\n"); EXPECT_NONFATAL_FAILURE({ return; }, ""); } #if GTEST_HAS_EXCEPTIONS // Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being // tested throws. TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows) { printf("(expecting a failure)\n"); try { EXPECT_NONFATAL_FAILURE({ throw 0; }, ""); } catch(int) { // NOLINT } } #endif // GTEST_HAS_EXCEPTIONS // Tests that EXPECT_FATAL_FAILURE() can reference global variables. TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables) { global_integer = 0; EXPECT_FATAL_FAILURE({ ASSERT_EQ(1, global_integer) << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() can reference local static // variables. TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables) { static int n; n = 1; EXPECT_FATAL_FAILURE({ ASSERT_EQ(0, n) << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly // one fatal failure and no non-fatal failure. TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure) { EXPECT_FATAL_FAILURE({ FAIL() << "Expected fatal failure."; }, "Expected fatal failure."); } // Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal // failure. TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ }, ""); } // A helper for generating a fatal failure. void FatalFailure() { FAIL() << "Expected fatal failure."; } // Tests that EXPECT_FATAL_FAILURE() fails when there are two // fatal failures. TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ FatalFailure(); FatalFailure(); }, ""); } // Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal // failure. TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ ADD_FAILURE() << "Expected non-fatal failure."; }, ""); } // Tests that EXPECT_FATAL_FAILURE() fails when the statement being // tested returns. TEST(ExpectFatalFailureTest, FailsWhenStatementReturns) { printf("(expecting a failure)\n"); EXPECT_FATAL_FAILURE({ return; }, ""); } #if GTEST_HAS_EXCEPTIONS // Tests that EXPECT_FATAL_FAILURE() fails when the statement being // tested throws. TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) { printf("(expecting a failure)\n"); try { EXPECT_FATAL_FAILURE({ throw 0; }, ""); } catch(int) { // NOLINT } } #endif // GTEST_HAS_EXCEPTIONS // This #ifdef block tests the output of typed tests. #if GTEST_HAS_TYPED_TEST template class TypedTest : public testing::Test { }; TYPED_TEST_CASE(TypedTest, testing::Types); TYPED_TEST(TypedTest, Success) { EXPECT_EQ(0, TypeParam()); } TYPED_TEST(TypedTest, Failure) { EXPECT_EQ(1, TypeParam()) << "Expected failure"; } #endif // GTEST_HAS_TYPED_TEST // This #ifdef block tests the output of type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P template class TypedTestP : public testing::Test { }; TYPED_TEST_CASE_P(TypedTestP); TYPED_TEST_P(TypedTestP, Success) { EXPECT_EQ(0U, TypeParam()); } TYPED_TEST_P(TypedTestP, Failure) { EXPECT_EQ(1U, TypeParam()) << "Expected failure"; } REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure); typedef testing::Types UnsignedTypes; INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes); #endif // GTEST_HAS_TYPED_TEST_P #if GTEST_HAS_DEATH_TEST // We rely on the golden file to verify that tests whose test case // name ends with DeathTest are run first. TEST(ADeathTest, ShouldRunFirst) { } # if GTEST_HAS_TYPED_TEST // We rely on the golden file to verify that typed tests whose test // case name ends with DeathTest are run first. template class ATypedDeathTest : public testing::Test { }; typedef testing::Types NumericTypes; TYPED_TEST_CASE(ATypedDeathTest, NumericTypes); TYPED_TEST(ATypedDeathTest, ShouldRunFirst) { } # endif // GTEST_HAS_TYPED_TEST # if GTEST_HAS_TYPED_TEST_P // We rely on the golden file to verify that type-parameterized tests // whose test case name ends with DeathTest are run first. template class ATypeParamDeathTest : public testing::Test { }; TYPED_TEST_CASE_P(ATypeParamDeathTest); TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) { } REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst); INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes); # endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_HAS_DEATH_TEST // Tests various failure conditions of // EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}. class ExpectFailureTest : public testing::Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. enum FailureMode { FATAL_FAILURE, NONFATAL_FAILURE }; static void AddFailure(FailureMode failure) { if (failure == FATAL_FAILURE) { FAIL() << "Expected fatal failure."; } else { ADD_FAILURE() << "Expected non-fatal failure."; } } }; TEST_F(ExpectFailureTest, ExpectFatalFailure) { // Expected fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure."); // Expected fatal failure, but got a non-fatal failure. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal " "failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure " "expected."); } TEST_F(ExpectFailureTest, ExpectNonFatalFailure) { // Expected non-fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure."); // Expected non-fatal failure, but got a fatal failure. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal " "failure."); } #if GTEST_IS_THREADSAFE class ExpectFailureWithThreadsTest : public ExpectFailureTest { protected: static void AddFailureInOtherThread(FailureMode failure) { ThreadWithParam thread(&AddFailure, failure, NULL); thread.Join(); } }; TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure) { // We only intercept the current thread. printf("(expecting 2 failures)\n"); EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE), "Expected fatal failure."); } TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure) { // We only intercept the current thread. printf("(expecting 2 failures)\n"); EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); } typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest; // Tests that the ScopedFakeTestPartResultReporter only catches failures from // the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD. TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) { printf("(expecting 2 failures)\n"); TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, &results); AddFailureInOtherThread(FATAL_FAILURE); AddFailureInOtherThread(NONFATAL_FAILURE); } // The two failures should not have been intercepted. EXPECT_EQ(0, results.size()) << "This shouldn't fail."; } #endif // GTEST_IS_THREADSAFE TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { // Expected fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure."); // Expected fatal failure, but got a non-fatal failure. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), "Expected non-fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), "Some other fatal failure expected."); } TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) { // Expected non-fatal failure, but succeeds. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal " "failure."); // Expected non-fatal failure, but got a fatal failure. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), "Expected fatal failure."); // Wrong message. printf("(expecting 1 failure)\n"); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), "Some other non-fatal failure."); } // Two test environments for testing testing::AddGlobalTestEnvironment(). class FooEnvironment : public testing::Environment { public: virtual void SetUp() { printf("%s", "FooEnvironment::SetUp() called.\n"); } virtual void TearDown() { printf("%s", "FooEnvironment::TearDown() called.\n"); FAIL() << "Expected fatal failure."; } }; class BarEnvironment : public testing::Environment { public: virtual void SetUp() { printf("%s", "BarEnvironment::SetUp() called.\n"); } virtual void TearDown() { printf("%s", "BarEnvironment::TearDown() called.\n"); ADD_FAILURE() << "Expected non-fatal failure."; } }; bool GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = false; // The main function. // // The idea is to use Google Test to run all the tests we have defined (some // of them are intended to fail), and then compare the test results // with the "golden" file. int main(int argc, char **argv) { testing::GTEST_FLAG(print_time) = false; // We just run the tests, knowing some of them are intended to fail. // We will use a separate Python script to compare the output of // this program with the golden file. // It's hard to test InitGoogleTest() directly, as it has many // global side effects. The following line serves as a sanity test // for it. testing::InitGoogleTest(&argc, argv); if (argc >= 2 && (std::string(argv[1]) == "--gtest_internal_skip_environment_and_ad_hoc_tests")) GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = true; #if GTEST_HAS_DEATH_TEST if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") { // Skip the usual output capturing if we're running as the child // process of an threadsafe-style death test. # if GTEST_OS_WINDOWS posix::FReopen("nul:", "w", stdout); # else posix::FReopen("/dev/null", "w", stdout); # endif // GTEST_OS_WINDOWS return RUN_ALL_TESTS(); } #endif // GTEST_HAS_DEATH_TEST if (GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests)) return RUN_ALL_TESTS(); // Registers two global test environments. // The golden file verifies that they are set up in the order they // are registered, and torn down in the reverse order. testing::AddGlobalTestEnvironment(new FooEnvironment); testing::AddGlobalTestEnvironment(new BarEnvironment); return RunAllTests(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_output_test_golden_lin.txt000066400000000000000000000670041273231111400326150ustar00rootroot00000000000000The non-test part of the code is expected to have 2 failures. gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true gtest_output_test_.cc:#: Failure Value of: 3 Expected: 2 [==========] Running 63 tests from 28 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. [----------] 1 test from ADeathTest [ RUN ] ADeathTest.ShouldRunFirst [ OK ] ADeathTest.ShouldRunFirst [----------] 1 test from ATypedDeathTest/0, where TypeParam = int [ RUN ] ATypedDeathTest/0.ShouldRunFirst [ OK ] ATypedDeathTest/0.ShouldRunFirst [----------] 1 test from ATypedDeathTest/1, where TypeParam = double [ RUN ] ATypedDeathTest/1.ShouldRunFirst [ OK ] ATypedDeathTest/1.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int [ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst [----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double [ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst [ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst [----------] 2 tests from PassingTest [ RUN ] PassingTest.PassingTest1 [ OK ] PassingTest.PassingTest1 [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] 1 test from NonfatalFailureTest [ RUN ] NonfatalFailureTest.EscapesStringOperands gtest_output_test_.cc:#: Failure Value of: actual Actual: "actual \"string\"" Expected: kGoldenString Which is: "\"Line" gtest_output_test_.cc:#: Failure Value of: actual Actual: "actual \"string\"" Expected: golden Which is: "\"Line" [ FAILED ] NonfatalFailureTest.EscapesStringOperands [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [----------] 6 tests from SCOPED_TRACETest [ RUN ] SCOPED_TRACETest.ObeysScopes (expected to fail) gtest_output_test_.cc:#: Failure Failed This failure is expected, and shouldn't have a trace. gtest_output_test_.cc:#: Failure Failed This failure is expected, and should have a trace. Google Test trace: gtest_output_test_.cc:#: Expected trace gtest_output_test_.cc:#: Failure Failed This failure is expected, and shouldn't have a trace. [ FAILED ] SCOPED_TRACETest.ObeysScopes [ RUN ] SCOPED_TRACETest.WorksInLoop (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: i = 1 gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: i = 2 [ FAILED ] SCOPED_TRACETest.WorksInLoop [ RUN ] SCOPED_TRACETest.WorksInSubroutine (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 1 Expected: 2 Google Test trace: gtest_output_test_.cc:#: n = 1 gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ RUN ] SCOPED_TRACETest.CanBeNested (expected to fail) gtest_output_test_.cc:#: Failure Value of: n Actual: 2 Expected: 1 Google Test trace: gtest_output_test_.cc:#: n = 2 gtest_output_test_.cc:#: [ FAILED ] SCOPED_TRACETest.CanBeNested [ RUN ] SCOPED_TRACETest.CanBeRepeated (expected to fail) gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A. Google Test trace: gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A and B. Google Test trace: gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A, B, and C. Google Test trace: gtest_output_test_.cc:#: C gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A gtest_output_test_.cc:#: Failure Failed This failure is expected, and should contain trace point A, B, and D. Google Test trace: gtest_output_test_.cc:#: D gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ RUN ] SCOPED_TRACETest.WorksConcurrently (expecting 6 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1 (in thread B, only trace B alive). Google Test trace: gtest_output_test_.cc:#: Trace B gtest_output_test_.cc:#: Failure Failed Expected failure #2 (in thread A, trace A & B both alive). Google Test trace: gtest_output_test_.cc:#: Trace A gtest_output_test_.cc:#: Failure Failed Expected failure #3 (in thread B, trace A & B both alive). Google Test trace: gtest_output_test_.cc:#: Trace B gtest_output_test_.cc:#: Failure Failed Expected failure #4 (in thread B, only trace A alive). gtest_output_test_.cc:#: Failure Failed Expected failure #5 (in thread A, only trace A alive). Google Test trace: gtest_output_test_.cc:#: Trace A gtest_output_test_.cc:#: Failure Failed Expected failure #6 (in thread A, no trace alive). [ FAILED ] SCOPED_TRACETest.WorksConcurrently [----------] 1 test from NonFatalFailureInFixtureConstructorTest [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: Failure Failed Expected failure #2, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #3, in the test body. gtest_output_test_.cc:#: Failure Failed Expected failure #4, in TearDown. gtest_output_test_.cc:#: Failure Failed Expected failure #5, in the test fixture d'tor. [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from FatalFailureInFixtureConstructorTest [ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in the test fixture c'tor. gtest_output_test_.cc:#: Failure Failed Expected failure #2, in the test fixture d'tor. [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [----------] 1 test from NonFatalFailureInSetUpTest [ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp (expecting 4 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #2, in the test function. gtest_output_test_.cc:#: Failure Failed Expected failure #3, in TearDown(). gtest_output_test_.cc:#: Failure Failed Expected failure #4, in the test fixture d'tor. [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [----------] 1 test from FatalFailureInSetUpTest [ RUN ] FatalFailureInSetUpTest.FailureInSetUp (expecting 3 failures) gtest_output_test_.cc:#: Failure Failed Expected failure #1, in SetUp(). gtest_output_test_.cc:#: Failure Failed Expected failure #2, in TearDown(). gtest_output_test_.cc:#: Failure Failed Expected failure #3, in the test fixture d'tor. [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [----------] 1 test from AddFailureAtTest [ RUN ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber foo.cc:42: Failure Failed Expected failure in foo.cc [ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber [----------] 4 tests from MixedUpTestCaseTest [ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo [ RUN ] MixedUpTestCaseTest.ThisShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ RUN ] MixedUpTestCaseTest.ThisShouldFailToo gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseTest, you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [----------] 2 tests from MixedUpTestCaseWithSameTestNameTest [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class. However, in test case MixedUpTestCaseWithSameTestNameTest, you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail using two different test fixture classes. This can happen if the two classes are from different namespaces or translation units and have the same name. You should probably rename one of the classes to put the tests into different test cases. [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [----------] 2 tests from TEST_F_before_TEST_in_same_test_case [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F [ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_F_before_TEST_in_same_test_case, test DefinedUsingTEST_F is defined using TEST_F but test DefinedUsingTESTAndShouldFail is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [----------] 2 tests from TEST_before_TEST_F_in_same_test_case [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST [ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail gtest.cc:#: Failure Failed All tests in the same test case must use the same test fixture class, so mixing TEST_F and TEST in the same test case is illegal. In test case TEST_before_TEST_F_in_same_test_case, test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but test DefinedUsingTEST is defined using TEST. You probably want to change the TEST to TEST_F or move it to another test case. [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [----------] 8 tests from ExpectNonfatalFailureTest [ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables [ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 2 failures gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 1. gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure 2. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [----------] 8 tests from ExpectFatalFailureTest [ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables [ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables [ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 2 failures gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows (expecting a failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [----------] 2 tests from TypedTest/0, where TypeParam = int [ RUN ] TypedTest/0.Success [ OK ] TypedTest/0.Success [ RUN ] TypedTest/0.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: 0 Expected: 1 Expected failure [ FAILED ] TypedTest/0.Failure, where TypeParam = int [----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char [ RUN ] Unsigned/TypedTestP/0.Success [ OK ] Unsigned/TypedTestP/0.Success [ RUN ] Unsigned/TypedTestP/0.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: '\0' Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char [----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int [ RUN ] Unsigned/TypedTestP/1.Success [ OK ] Unsigned/TypedTestP/1.Success [ RUN ] Unsigned/TypedTestP/1.Failure gtest_output_test_.cc:#: Failure Value of: TypeParam() Actual: 0 Expected: 1U Which is: 1 Expected failure [ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int [----------] 4 tests from ExpectFailureTest [ RUN ] ExpectFailureTest.ExpectFatalFailure (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ RUN ] ExpectFailureTest.ExpectNonFatalFailure (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 fatal failure containing "Some other fatal failure expected." Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Success: Succeeded (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: gtest_output_test_.cc:#: Fatal failure: Failed Expected fatal failure. (expecting 1 failure) gtest.cc:#: Failure Expected: 1 non-fatal failure containing "Some other non-fatal failure." Actual: gtest_output_test_.cc:#: Non-fatal failure: Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads [----------] 2 tests from ExpectFailureWithThreadsTest [ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected fatal failure. gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure [ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. gtest.cc:#: Failure Expected: 1 non-fatal failure Actual: 0 failures [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [----------] 1 test from ScopedFakeTestPartResultReporterTest [ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread (expecting 2 failures) gtest_output_test_.cc:#: Failure Failed Expected fatal failure. gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [----------] 1 test from PrintingFailingParams/FailingParamTest [ RUN ] PrintingFailingParams/FailingParamTest.Fails/0 gtest_output_test_.cc:#: Failure Value of: GetParam() Actual: 2 Expected: 1 [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected non-fatal failure. FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. [==========] 63 tests from 28 test cases ran. [ PASSED ] 21 tests. [ FAILED ] 42 tests, listed below: [ FAILED ] NonfatalFailureTest.EscapesStringOperands [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [ FAILED ] SCOPED_TRACETest.ObeysScopes [ FAILED ] SCOPED_TRACETest.WorksInLoop [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeRepeated [ FAILED ] SCOPED_TRACETest.WorksConcurrently [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [ FAILED ] FatalFailureInSetUpTest.FailureInSetUp [ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber [ FAILED ] MixedUpTestCaseTest.ThisShouldFail [ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo [ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail [ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail [ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures [ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows [ FAILED ] TypedTest/0.Failure, where TypeParam = int [ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char [ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int [ FAILED ] ExpectFailureTest.ExpectFatalFailure [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads [ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 42 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* [==========] Running 4 tests from 2 test cases. [----------] Global test environment set-up. [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Value of: x Actual: 2 Expected: 1 [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms) [ RUN ] FatalFailureTest.NonfatalFailureInSubroutine (expecting a failure on false) gtest_output_test_.cc:#: Failure Value of: false Actual: false Expected: true [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms) [----------] 3 tests from FatalFailureTest (? ms total) [----------] 1 test from LoggingTest [ RUN ] LoggingTest.InterleavingLoggingAndAssertions (expecting 2 failures on (3) >= (a[i])) i == 0 i == 1 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 9 i == 2 i == 3 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 6 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms) [----------] 1 test from LoggingTest (? ms total) [----------] Global test environment tear-down [==========] 4 tests from 2 test cases ran. (? ms total) [ PASSED ] 0 tests. [ FAILED ] 4 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions 4 FAILED TESTS Note: Google Test filter = *DISABLED_* [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from DisabledTestsWarningTest [ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. Note: Google Test filter = PassingTest.* Note: This is test shard 2 of 2. [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from PassingTest [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. [ PASSED ] 1 test. mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_pred_impl_unittest.cc000066400000000000000000002271021273231111400315010ustar00rootroot00000000000000// 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! // Regression test for gtest_pred_impl.h // // This file is generated by a script and quite long. If you intend to // learn how Google Test works by reading its unit tests, read // gtest_unittest.cc instead. // // This is intended as a regression test for the Google Test predicate // assertions. We compile it as part of the gtest_unittest target // only to keep the implementation tidy and compact, as it is quite // involved to set up the stage for testing Google Test using Google // Test itself. // // Currently, gtest_unittest takes ~11 seconds to run in the testing // daemon. In the future, if it grows too large and needs much more // time to finish, we should consider separating this file into a // stand-alone regression test. #include #include "gtest/gtest.h" #include "gtest/gtest-spi.h" // A user-defined data type. struct Bool { explicit Bool(int val) : value(val != 0) {} bool operator>(int n) const { return value > Bool(n).value; } Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } bool operator==(const Bool& rhs) const { return value == rhs.value; } bool value; }; // Enables Bool to be used in assertions. std::ostream& operator<<(std::ostream& os, const Bool& x) { return os << (x.value ? "true" : "false"); } // Sample functions/functors for testing unary predicate assertions. // A unary predicate function. template bool PredFunction1(T1 v1) { return v1 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction1Int(int v1) { return v1 > 0; } bool PredFunction1Bool(Bool v1) { return v1 > 0; } // A unary predicate functor. struct PredFunctor1 { template bool operator()(const T1& v1) { return v1 > 0; } }; // A unary predicate-formatter function. template testing::AssertionResult PredFormatFunction1(const char* e1, const T1& v1) { if (PredFunction1(v1)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " is expected to be positive, but evaluates to " << v1 << "."; } // A unary predicate-formatter functor. struct PredFormatFunctor1 { template testing::AssertionResult operator()(const char* e1, const T1& v1) const { return PredFormatFunction1(e1, v1); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT1. class Predicate1Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; }; bool Predicate1Test::expected_to_finish_; bool Predicate1Test::finished_; int Predicate1Test::n1_; typedef Predicate1Test EXPECT_PRED_FORMAT1Test; typedef Predicate1Test ASSERT_PRED_FORMAT1Test; typedef Predicate1Test EXPECT_PRED1Test; typedef Predicate1Test ASSERT_PRED1Test; // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED1(PredFunction1Int, ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess) { EXPECT_PRED1(PredFunction1Bool, Bool(++n1_)); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED1(PredFunctor1(), ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess) { EXPECT_PRED1(PredFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunction1Int, n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunction1Bool, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(PredFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED1(PredFunction1Int, ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess) { ASSERT_PRED1(PredFunction1Bool, Bool(++n1_)); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED1(PredFunctor1(), ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess) { ASSERT_PRED1(PredFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunction1Int, n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunction1Bool, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED1(PredFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunction1, ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunction1, Bool(++n1_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunctor1(), ++n1_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT1(PredFormatFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunction1, n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunction1, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT1(PredFormatFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunction1, ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunction1, Bool(++n1_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunctor1(), ++n1_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT1(PredFormatFunctor1(), Bool(++n1_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunction1, n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunction1, Bool(n1_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunctor1(), n1_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT1 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(PredFormatFunctor1(), Bool(n1_++)); finished_ = true; }, ""); } // Sample functions/functors for testing binary predicate assertions. // A binary predicate function. template bool PredFunction2(T1 v1, T2 v2) { return v1 + v2 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction2Int(int v1, int v2) { return v1 + v2 > 0; } bool PredFunction2Bool(Bool v1, Bool v2) { return v1 + v2 > 0; } // A binary predicate functor. struct PredFunctor2 { template bool operator()(const T1& v1, const T2& v2) { return v1 + v2 > 0; } }; // A binary predicate-formatter function. template testing::AssertionResult PredFormatFunction2(const char* e1, const char* e2, const T1& v1, const T2& v2) { if (PredFunction2(v1, v2)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " + " << e2 << " is expected to be positive, but evaluates to " << v1 + v2 << "."; } // A binary predicate-formatter functor. struct PredFormatFunctor2 { template testing::AssertionResult operator()(const char* e1, const char* e2, const T1& v1, const T2& v2) const { return PredFormatFunction2(e1, e2, v1, v2); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT2. class Predicate2Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; }; bool Predicate2Test::expected_to_finish_; bool Predicate2Test::finished_; int Predicate2Test::n1_; int Predicate2Test::n2_; typedef Predicate2Test EXPECT_PRED_FORMAT2Test; typedef Predicate2Test ASSERT_PRED_FORMAT2Test; typedef Predicate2Test EXPECT_PRED2Test; typedef Predicate2Test ASSERT_PRED2Test; // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED2(PredFunction2Int, ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess) { EXPECT_PRED2(PredFunction2Bool, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED2(PredFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess) { EXPECT_PRED2(PredFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunction2Int, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunction2Bool, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(PredFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED2(PredFunction2Int, ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess) { ASSERT_PRED2(PredFunction2Bool, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED2(PredFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess) { ASSERT_PRED2(PredFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunction2Int, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunction2Bool, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED2(PredFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunction2, ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunction2, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT2(PredFormatFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunction2, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunction2, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(PredFormatFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunction2, ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunction2, Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunctor2(), ++n1_, ++n2_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT2(PredFormatFunctor2(), Bool(++n1_), Bool(++n2_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunction2, n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunction2, Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunctor2(), n1_++, n2_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT2 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(PredFormatFunctor2(), Bool(n1_++), Bool(n2_++)); finished_ = true; }, ""); } // Sample functions/functors for testing ternary predicate assertions. // A ternary predicate function. template bool PredFunction3(T1 v1, T2 v2, T3 v3) { return v1 + v2 + v3 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction3Int(int v1, int v2, int v3) { return v1 + v2 + v3 > 0; } bool PredFunction3Bool(Bool v1, Bool v2, Bool v3) { return v1 + v2 + v3 > 0; } // A ternary predicate functor. struct PredFunctor3 { template bool operator()(const T1& v1, const T2& v2, const T3& v3) { return v1 + v2 + v3 > 0; } }; // A ternary predicate-formatter function. template testing::AssertionResult PredFormatFunction3(const char* e1, const char* e2, const char* e3, const T1& v1, const T2& v2, const T3& v3) { if (PredFunction3(v1, v2, v3)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 << "."; } // A ternary predicate-formatter functor. struct PredFormatFunctor3 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const T1& v1, const T2& v2, const T3& v3) const { return PredFormatFunction3(e1, e2, e3, v1, v2, v3); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT3. class Predicate3Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; }; bool Predicate3Test::expected_to_finish_; bool Predicate3Test::finished_; int Predicate3Test::n1_; int Predicate3Test::n2_; int Predicate3Test::n3_; typedef Predicate3Test EXPECT_PRED_FORMAT3Test; typedef Predicate3Test ASSERT_PRED_FORMAT3Test; typedef Predicate3Test EXPECT_PRED3Test; typedef Predicate3Test ASSERT_PRED3Test; // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED3(PredFunction3Int, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess) { EXPECT_PRED3(PredFunction3Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED3(PredFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess) { EXPECT_PRED3(PredFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunction3Int, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunction3Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(PredFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED3(PredFunction3Int, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess) { ASSERT_PRED3(PredFunction3Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED3(PredFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess) { ASSERT_PRED3(PredFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunction3Int, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunction3Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(PredFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunction3, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunction3, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT3(PredFormatFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunction3, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunction3, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT3(PredFormatFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunction3, ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunction3, Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunctor3(), ++n1_, ++n2_, ++n3_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT3(PredFormatFunctor3(), Bool(++n1_), Bool(++n2_), Bool(++n3_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunction3, n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunction3, Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunctor3(), n1_++, n2_++, n3_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT3 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT3(PredFormatFunctor3(), Bool(n1_++), Bool(n2_++), Bool(n3_++)); finished_ = true; }, ""); } // Sample functions/functors for testing 4-ary predicate assertions. // A 4-ary predicate function. template bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4) { return v1 + v2 + v3 + v4 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction4Int(int v1, int v2, int v3, int v4) { return v1 + v2 + v3 + v4 > 0; } bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4) { return v1 + v2 + v3 + v4 > 0; } // A 4-ary predicate functor. struct PredFunctor4 { template bool operator()(const T1& v1, const T2& v2, const T3& v3, const T4& v4) { return v1 + v2 + v3 + v4 > 0; } }; // A 4-ary predicate-formatter function. template testing::AssertionResult PredFormatFunction4(const char* e1, const char* e2, const char* e3, const char* e4, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (PredFunction4(v1, v2, v3, v4)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 << "."; } // A 4-ary predicate-formatter functor. struct PredFormatFunctor4 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const char* e4, const T1& v1, const T2& v2, const T3& v3, const T4& v4) const { return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT4. class Predicate4Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = n4_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; EXPECT_EQ(1, n4_) << "The predicate assertion didn't evaluate argument 5 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; static int n4_; }; bool Predicate4Test::expected_to_finish_; bool Predicate4Test::finished_; int Predicate4Test::n1_; int Predicate4Test::n2_; int Predicate4Test::n3_; int Predicate4Test::n4_; typedef Predicate4Test EXPECT_PRED_FORMAT4Test; typedef Predicate4Test ASSERT_PRED_FORMAT4Test; typedef Predicate4Test EXPECT_PRED4Test; typedef Predicate4Test ASSERT_PRED4Test; // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED4(PredFunction4Int, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess) { EXPECT_PRED4(PredFunction4Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED4(PredFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess) { EXPECT_PRED4(PredFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunction4Int, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunction4Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED4(PredFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED4(PredFunction4Int, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess) { ASSERT_PRED4(PredFunction4Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED4(PredFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess) { ASSERT_PRED4(PredFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunction4Int, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunction4Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED4(PredFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunction4, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunction4, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT4(PredFormatFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunction4, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunction4, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(PredFormatFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunction4, ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunction4, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunctor4(), ++n1_, ++n2_, ++n3_, ++n4_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT4(PredFormatFunctor4(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunction4, n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunction4, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunctor4(), n1_++, n2_++, n3_++, n4_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT4 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT4(PredFormatFunctor4(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++)); finished_ = true; }, ""); } // Sample functions/functors for testing 5-ary predicate assertions. // A 5-ary predicate function. template bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return v1 + v2 + v3 + v4 + v5 > 0; } // The following two functions are needed to circumvent a bug in // gcc 2.95.3, which sometimes has problem with the above template // function. bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5) { return v1 + v2 + v3 + v4 + v5 > 0; } bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5) { return v1 + v2 + v3 + v4 + v5 > 0; } // A 5-ary predicate functor. struct PredFunctor5 { template bool operator()(const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { return v1 + v2 + v3 + v4 + v5 > 0; } }; // A 5-ary predicate-formatter function. template testing::AssertionResult PredFormatFunction5(const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (PredFunction5(v1, v2, v3, v4, v5)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 + v5 << "."; } // A 5-ary predicate-formatter functor. struct PredFormatFunctor5 { template testing::AssertionResult operator()(const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) const { return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5); } }; // Tests for {EXPECT|ASSERT}_PRED_FORMAT5. class Predicate5Test : public testing::Test { protected: virtual void SetUp() { expected_to_finish_ = true; finished_ = false; n1_ = n2_ = n3_ = n4_ = n5_ = 0; } virtual void TearDown() { // Verifies that each of the predicate's arguments was evaluated // exactly once. EXPECT_EQ(1, n1_) << "The predicate assertion didn't evaluate argument 2 " "exactly once."; EXPECT_EQ(1, n2_) << "The predicate assertion didn't evaluate argument 3 " "exactly once."; EXPECT_EQ(1, n3_) << "The predicate assertion didn't evaluate argument 4 " "exactly once."; EXPECT_EQ(1, n4_) << "The predicate assertion didn't evaluate argument 5 " "exactly once."; EXPECT_EQ(1, n5_) << "The predicate assertion didn't evaluate argument 6 " "exactly once."; // Verifies that the control flow in the test function is expected. if (expected_to_finish_ && !finished_) { FAIL() << "The predicate assertion unexpactedly aborted the test."; } else if (!expected_to_finish_ && finished_) { FAIL() << "The failed predicate assertion didn't abort the test " "as expected."; } } // true iff the test function is expected to run to finish. static bool expected_to_finish_; // true iff the test function did run to finish. static bool finished_; static int n1_; static int n2_; static int n3_; static int n4_; static int n5_; }; bool Predicate5Test::expected_to_finish_; bool Predicate5Test::finished_; int Predicate5Test::n1_; int Predicate5Test::n2_; int Predicate5Test::n3_; int Predicate5Test::n4_; int Predicate5Test::n5_; typedef Predicate5Test EXPECT_PRED_FORMAT5Test; typedef Predicate5Test ASSERT_PRED_FORMAT5Test; typedef Predicate5Test EXPECT_PRED5Test; typedef Predicate5Test ASSERT_PRED5Test; // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED5(PredFunction5Int, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess) { EXPECT_PRED5(PredFunction5Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED5(PredFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess) { EXPECT_PRED5(PredFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunction5Int, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunction5Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED5(PredFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED5(PredFunction5Int, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess) { ASSERT_PRED5(PredFunction5Bool, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED5(PredFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess) { ASSERT_PRED5(PredFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunction5Int, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunction5Bool, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED5(PredFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunction5, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunction5, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { EXPECT_PRED_FORMAT5(PredFormatFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunction5, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunction5, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed EXPECT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT5(PredFormatFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunction5, ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunction5, Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunctor5(), ++n1_, ++n2_, ++n3_, ++n4_, ++n5_); finished_ = true; } // Tests a successful ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { ASSERT_PRED_FORMAT5(PredFormatFunctor5(), Bool(++n1_), Bool(++n2_), Bool(++n3_), Bool(++n4_), Bool(++n5_)); finished_ = true; } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunction5, n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a function on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunction5, Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a built-in type (int). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunctor5(), n1_++, n2_++, n3_++, n4_++, n5_++); finished_ = true; }, ""); } // Tests a failed ASSERT_PRED_FORMAT5 where the // predicate-formatter is a functor on a user-defined type (Bool). TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { expected_to_finish_ = false; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(PredFormatFunctor5(), Bool(n1_++), Bool(n2_++), Bool(n3_++), Bool(n4_++), Bool(n5_++)); finished_ = true; }, ""); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_premature_exit_test.cc000066400000000000000000000112441273231111400316610ustar00rootroot00000000000000// Copyright 2013, 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) // // Tests that Google Test manipulates the premature-exit-detection // file correctly. #include #include "gtest/gtest.h" using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::internal::posix::GetEnv; using ::testing::internal::posix::Stat; using ::testing::internal::posix::StatStruct; namespace { // Is the TEST_PREMATURE_EXIT_FILE environment variable expected to be // set? const bool kTestPrematureExitFileEnvVarShouldBeSet = false; class PrematureExitTest : public Test { public: // Returns true iff the given file exists. static bool FileExists(const char* filepath) { StatStruct stat; return Stat(filepath, &stat) == 0; } protected: PrematureExitTest() { premature_exit_file_path_ = GetEnv("TEST_PREMATURE_EXIT_FILE"); // Normalize NULL to "" for ease of handling. if (premature_exit_file_path_ == NULL) { premature_exit_file_path_ = ""; } } // Returns true iff the premature-exit file exists. bool PrematureExitFileExists() const { return FileExists(premature_exit_file_path_); } const char* premature_exit_file_path_; }; typedef PrematureExitTest PrematureExitDeathTest; // Tests that: // - the premature-exit file exists during the execution of a // death test (EXPECT_DEATH*), and // - a death test doesn't interfere with the main test process's // handling of the premature-exit file. TEST_F(PrematureExitDeathTest, FileExistsDuringExecutionOfDeathTest) { if (*premature_exit_file_path_ == '\0') { return; } EXPECT_DEATH_IF_SUPPORTED({ // If the file exists, crash the process such that the main test // process will catch the (expected) crash and report a success; // otherwise don't crash, which will cause the main test process // to report that the death test has failed. if (PrematureExitFileExists()) { exit(1); } }, ""); } // Tests that TEST_PREMATURE_EXIT_FILE is set where it's expected to // be set. TEST_F(PrematureExitTest, TestPrematureExitFileEnvVarIsSet) { if (kTestPrematureExitFileEnvVarShouldBeSet) { const char* const filepath = GetEnv("TEST_PREMATURE_EXIT_FILE"); ASSERT_TRUE(filepath != NULL); ASSERT_NE(*filepath, '\0'); } } // Tests that the premature-exit file exists during the execution of a // normal (non-death) test. TEST_F(PrematureExitTest, PrematureExitFileExistsDuringTestExecution) { if (*premature_exit_file_path_ == '\0') { return; } EXPECT_TRUE(PrematureExitFileExists()) << " file " << premature_exit_file_path_ << " should exist during test execution, but doesn't."; } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); const int exit_code = RUN_ALL_TESTS(); // Test that the premature-exit file is deleted upon return from // RUN_ALL_TESTS(). const char* const filepath = GetEnv("TEST_PREMATURE_EXIT_FILE"); if (filepath != NULL && *filepath != '\0') { if (PrematureExitTest::FileExists(filepath)) { printf( "File %s shouldn't exist after the test program finishes, but does.", filepath); return 1; } } return exit_code; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_prod_test.cc000066400000000000000000000042411273231111400275670ustar00rootroot00000000000000// 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) // // Unit test for include/gtest/gtest_prod.h. #include "gtest/gtest.h" #include "test/production.h" // Tests that private members can be accessed from a TEST declared as // a friend of the class. TEST(PrivateCodeTest, CanAccessPrivateMembers) { PrivateCode a; EXPECT_EQ(0, a.x_); a.set_x(1); EXPECT_EQ(1, a.x_); } typedef testing::Test PrivateCodeFixtureTest; // Tests that private members can be accessed from a TEST_F declared // as a friend of the class. TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) { PrivateCode a; EXPECT_EQ(0, a.x_); a.set_x(2); EXPECT_EQ(2, a.x_); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_repeat_test.cc000066400000000000000000000200011273231111400300730ustar00rootroot00000000000000// 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) // Tests the --gtest_repeat=number flag. #include #include #include "gtest/gtest.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 { GTEST_DECLARE_string_(death_test_style); GTEST_DECLARE_string_(filter); GTEST_DECLARE_int32_(repeat); } // namespace testing using testing::GTEST_FLAG(death_test_style); using testing::GTEST_FLAG(filter); using testing::GTEST_FLAG(repeat); namespace { // We need this when we are testing Google Test itself and therefore // cannot use Google Test assertions. #define GTEST_CHECK_INT_EQ_(expected, actual) \ do {\ const int expected_val = (expected);\ const int actual_val = (actual);\ if (::testing::internal::IsTrue(expected_val != actual_val)) {\ ::std::cout << "Value of: " #actual "\n"\ << " Actual: " << actual_val << "\n"\ << "Expected: " #expected "\n"\ << "Which is: " << expected_val << "\n";\ ::testing::internal::posix::Abort();\ }\ } while (::testing::internal::AlwaysFalse()) // Used for verifying that global environment set-up and tear-down are // inside the gtest_repeat loop. int g_environment_set_up_count = 0; int g_environment_tear_down_count = 0; class MyEnvironment : public testing::Environment { public: MyEnvironment() {} virtual void SetUp() { g_environment_set_up_count++; } virtual void TearDown() { g_environment_tear_down_count++; } }; // A test that should fail. int g_should_fail_count = 0; TEST(FooTest, ShouldFail) { g_should_fail_count++; EXPECT_EQ(0, 1) << "Expected failure."; } // A test that should pass. int g_should_pass_count = 0; TEST(FooTest, ShouldPass) { g_should_pass_count++; } // A test that contains a thread-safe death test and a fast death // test. It should pass. int g_death_test_count = 0; TEST(BarDeathTest, ThreadSafeAndFast) { g_death_test_count++; GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); } #if GTEST_HAS_PARAM_TEST int g_param_test_count = 0; const int kNumberOfParamTests = 10; class MyParamTest : public testing::TestWithParam {}; TEST_P(MyParamTest, ShouldPass) { // TODO(vladl@google.com): Make parameter value checking robust // WRT order of tests. GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam()); g_param_test_count++; } INSTANTIATE_TEST_CASE_P(MyParamSequence, MyParamTest, testing::Range(0, kNumberOfParamTests)); #endif // GTEST_HAS_PARAM_TEST // Resets the count for each test. void ResetCounts() { g_environment_set_up_count = 0; g_environment_tear_down_count = 0; g_should_fail_count = 0; g_should_pass_count = 0; g_death_test_count = 0; #if GTEST_HAS_PARAM_TEST g_param_test_count = 0; #endif // GTEST_HAS_PARAM_TEST } // Checks that the count for each test is expected. void CheckCounts(int expected) { GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(expected, g_should_fail_count); GTEST_CHECK_INT_EQ_(expected, g_should_pass_count); GTEST_CHECK_INT_EQ_(expected, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } // Tests the behavior of Google Test when --gtest_repeat is not specified. void TestRepeatUnspecified() { ResetCounts(); GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); CheckCounts(1); } // Tests the behavior of Google Test when --gtest_repeat has the given value. void TestRepeat(int repeat) { GTEST_FLAG(repeat) = repeat; ResetCounts(); GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS()); CheckCounts(repeat); } // Tests using --gtest_repeat when --gtest_filter specifies an empty // set of tests. void TestRepeatWithEmptyFilter(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "None"; ResetCounts(); GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); CheckCounts(0); } // Tests using --gtest_repeat when --gtest_filter specifies a set of // successful tests. void TestRepeatWithFilterForSuccessfulTests(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "*-*ShouldFail"; ResetCounts(); GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(0, g_should_fail_count); GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count); GTEST_CHECK_INT_EQ_(repeat, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } // Tests using --gtest_repeat when --gtest_filter specifies a set of // failed tests. void TestRepeatWithFilterForFailedTests(int repeat) { GTEST_FLAG(repeat) = repeat; GTEST_FLAG(filter) = "*ShouldFail"; ResetCounts(); GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count); GTEST_CHECK_INT_EQ_(0, g_should_pass_count); GTEST_CHECK_INT_EQ_(0, g_death_test_count); #if GTEST_HAS_PARAM_TEST GTEST_CHECK_INT_EQ_(0, g_param_test_count); #endif // GTEST_HAS_PARAM_TEST } } // namespace int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); testing::AddGlobalTestEnvironment(new MyEnvironment); TestRepeatUnspecified(); TestRepeat(0); TestRepeat(1); TestRepeat(5); TestRepeatWithEmptyFilter(2); TestRepeatWithEmptyFilter(3); TestRepeatWithFilterForSuccessfulTests(3); TestRepeatWithFilterForFailedTests(4); // It would be nice to verify that the tests indeed loop forever // when GTEST_FLAG(repeat) is negative, but this test will be quite // complicated to write. Since this flag is for interactive // debugging only and doesn't affect the normal test result, such a // test would be an overkill. printf("PASS\n"); return 0; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_shuffle_test.py000077500000000000000000000304051273231111400303260ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2009 Google Inc. All Rights Reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Verifies that test shuffling works.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils # Command to run the gtest_shuffle_test_ program. COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_') # The environment variables for test sharding. TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' TEST_FILTER = 'A*.A:A*.B:C*' ALL_TESTS = [] ACTIVE_TESTS = [] FILTERED_TESTS = [] SHARDED_TESTS = [] SHUFFLED_ALL_TESTS = [] SHUFFLED_ACTIVE_TESTS = [] SHUFFLED_FILTERED_TESTS = [] SHUFFLED_SHARDED_TESTS = [] def AlsoRunDisabledTestsFlag(): return '--gtest_also_run_disabled_tests' def FilterFlag(test_filter): return '--gtest_filter=%s' % (test_filter,) def RepeatFlag(n): return '--gtest_repeat=%s' % (n,) def ShuffleFlag(): return '--gtest_shuffle' def RandomSeedFlag(n): return '--gtest_random_seed=%s' % (n,) def RunAndReturnOutput(extra_env, args): """Runs the test program and returns its output.""" environ_copy = os.environ.copy() environ_copy.update(extra_env) return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output def GetTestsForAllIterations(extra_env, args): """Runs the test program and returns a list of test lists. Args: extra_env: a map from environment variables to their values args: command line flags to pass to gtest_shuffle_test_ Returns: A list where the i-th element is the list of tests run in the i-th test iteration. """ test_iterations = [] for line in RunAndReturnOutput(extra_env, args).split('\n'): if line.startswith('----'): tests = [] test_iterations.append(tests) elif line.strip(): tests.append(line.strip()) # 'TestCaseName.TestName' return test_iterations def GetTestCases(tests): """Returns a list of test cases in the given full test names. Args: tests: a list of full test names Returns: A list of test cases from 'tests', in their original order. Consecutive duplicates are removed. """ test_cases = [] for test in tests: test_case = test.split('.')[0] if not test_case in test_cases: test_cases.append(test_case) return test_cases def CalculateTestLists(): """Calculates the list of tests run under different flags.""" if not ALL_TESTS: ALL_TESTS.extend( GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0]) if not ACTIVE_TESTS: ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0]) if not FILTERED_TESTS: FILTERED_TESTS.extend( GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0]) if not SHARDED_TESTS: SHARDED_TESTS.extend( GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [])[0]) if not SHUFFLED_ALL_TESTS: SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations( {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0]) if not SHUFFLED_ACTIVE_TESTS: SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) if not SHUFFLED_FILTERED_TESTS: SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0]) if not SHUFFLED_SHARDED_TESTS: SHUFFLED_SHARDED_TESTS.extend( GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) class GTestShuffleUnitTest(gtest_test_utils.TestCase): """Tests test shuffling.""" def setUp(self): CalculateTestLists() def testShufflePreservesNumberOfTests(self): self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS)) self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS)) self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS)) self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS)) def testShuffleChangesTestOrder(self): self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS) self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS) self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS, SHUFFLED_FILTERED_TESTS) self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS, SHUFFLED_SHARDED_TESTS) def testShuffleChangesTestCaseOrder(self): self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS), GetTestCases(SHUFFLED_ALL_TESTS)) self.assert_( GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS), GetTestCases(SHUFFLED_ACTIVE_TESTS)) self.assert_( GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS), GetTestCases(SHUFFLED_FILTERED_TESTS)) self.assert_( GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS), GetTestCases(SHUFFLED_SHARDED_TESTS)) def testShuffleDoesNotRepeatTest(self): for test in SHUFFLED_ALL_TESTS: self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_ACTIVE_TESTS: self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_FILTERED_TESTS: self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test), '%s appears more than once' % (test,)) for test in SHUFFLED_SHARDED_TESTS: self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test), '%s appears more than once' % (test,)) def testShuffleDoesNotCreateNewTest(self): for test in SHUFFLED_ALL_TESTS: self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_ACTIVE_TESTS: self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_FILTERED_TESTS: self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,)) for test in SHUFFLED_SHARDED_TESTS: self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,)) def testShuffleIncludesAllTests(self): for test in ALL_TESTS: self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,)) for test in ACTIVE_TESTS: self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,)) for test in FILTERED_TESTS: self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,)) for test in SHARDED_TESTS: self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,)) def testShuffleLeavesDeathTestsAtFront(self): non_death_test_found = False for test in SHUFFLED_ACTIVE_TESTS: if 'DeathTest.' in test: self.assert_(not non_death_test_found, '%s appears after a non-death test' % (test,)) else: non_death_test_found = True def _VerifyTestCasesDoNotInterleave(self, tests): test_cases = [] for test in tests: [test_case, _] = test.split('.') if test_cases and test_cases[-1] != test_case: test_cases.append(test_case) self.assertEqual(1, test_cases.count(test_case), 'Test case %s is not grouped together in %s' % (test_case, tests)) def testShuffleDoesNotInterleaveTestCases(self): self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS) self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS) def testShuffleRestoresOrderAfterEachIteration(self): # Get the test lists in all 3 iterations, using random seed 1, 2, # and 3 respectively. Google Test picks a different seed in each # iteration, and this test depends on the current implementation # picking successive numbers. This dependency is not ideal, but # makes the test much easier to write. [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) # Make sure running the tests with random seed 1 gets the same # order as in iteration 1 above. [tests_with_seed1] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1)]) self.assertEqual(tests_in_iteration1, tests_with_seed1) # Make sure running the tests with random seed 2 gets the same # order as in iteration 2 above. Success means that Google Test # correctly restores the test order before re-shuffling at the # beginning of iteration 2. [tests_with_seed2] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(2)]) self.assertEqual(tests_in_iteration2, tests_with_seed2) # Make sure running the tests with random seed 3 gets the same # order as in iteration 3 above. Success means that Google Test # correctly restores the test order before re-shuffling at the # beginning of iteration 3. [tests_with_seed3] = GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(3)]) self.assertEqual(tests_in_iteration3, tests_with_seed3) def testShuffleGeneratesNewOrderInEachIteration(self): [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( GetTestsForAllIterations( {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) self.assert_(tests_in_iteration1 != tests_in_iteration2, tests_in_iteration1) self.assert_(tests_in_iteration1 != tests_in_iteration3, tests_in_iteration1) self.assert_(tests_in_iteration2 != tests_in_iteration3, tests_in_iteration2) def testShuffleShardedTestsPreservesPartition(self): # If we run M tests on N shards, the same M tests should be run in # total, regardless of the random seeds used by the shards. [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '0'}, [ShuffleFlag(), RandomSeedFlag(1)]) [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '1'}, [ShuffleFlag(), RandomSeedFlag(20)]) [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', SHARD_INDEX_ENV_VAR: '2'}, [ShuffleFlag(), RandomSeedFlag(25)]) sorted_sharded_tests = tests1 + tests2 + tests3 sorted_sharded_tests.sort() sorted_active_tests = [] sorted_active_tests.extend(ACTIVE_TESTS) sorted_active_tests.sort() self.assertEqual(sorted_active_tests, sorted_sharded_tests) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_shuffle_test_.cc000066400000000000000000000063521273231111400304230ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Verifies that test shuffling works. #include "gtest/gtest.h" namespace { using ::testing::EmptyTestEventListener; using ::testing::InitGoogleTest; using ::testing::Message; using ::testing::Test; using ::testing::TestEventListeners; using ::testing::TestInfo; using ::testing::UnitTest; using ::testing::internal::scoped_ptr; // The test methods are empty, as the sole purpose of this program is // to print the test names before/after shuffling. class A : public Test {}; TEST_F(A, A) {} TEST_F(A, B) {} TEST(ADeathTest, A) {} TEST(ADeathTest, B) {} TEST(ADeathTest, C) {} TEST(B, A) {} TEST(B, B) {} TEST(B, C) {} TEST(B, DISABLED_D) {} TEST(B, DISABLED_E) {} TEST(BDeathTest, A) {} TEST(BDeathTest, B) {} TEST(C, A) {} TEST(C, B) {} TEST(C, C) {} TEST(C, DISABLED_D) {} TEST(CDeathTest, A) {} TEST(DISABLED_D, A) {} TEST(DISABLED_D, DISABLED_B) {} // This printer prints the full test names only, starting each test // iteration with a "----" marker. class TestNamePrinter : public EmptyTestEventListener { public: virtual void OnTestIterationStart(const UnitTest& /* unit_test */, int /* iteration */) { printf("----\n"); } virtual void OnTestStart(const TestInfo& test_info) { printf("%s.%s\n", test_info.test_case_name(), test_info.name()); } }; } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); // Replaces the default printer with TestNamePrinter, which prints // the test name only. TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); delete listeners.Release(listeners.default_result_printer()); listeners.Append(new TestNamePrinter); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_sole_header_test.cc000066400000000000000000000042551273231111400311020ustar00rootroot00000000000000// 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) // // This test verifies that it's possible to use Google Test by including // the gtest.h header file alone. #include "gtest/gtest.h" namespace { void Subroutine() { EXPECT_EQ(42, 42); } TEST(NoFatalFailureTest, ExpectNoFatalFailure) { EXPECT_NO_FATAL_FAILURE(;); EXPECT_NO_FATAL_FAILURE(SUCCEED()); EXPECT_NO_FATAL_FAILURE(Subroutine()); EXPECT_NO_FATAL_FAILURE({ SUCCEED(); }); } TEST(NoFatalFailureTest, AssertNoFatalFailure) { ASSERT_NO_FATAL_FAILURE(;); ASSERT_NO_FATAL_FAILURE(SUCCEED()); ASSERT_NO_FATAL_FAILURE(Subroutine()); ASSERT_NO_FATAL_FAILURE({ SUCCEED(); }); } } // namespace mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_stress_test.cc000066400000000000000000000226511273231111400301530ustar00rootroot00000000000000// 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) // Tests that SCOPED_TRACE() and various Google Test assertions can be // used in a large number of threads concurrently. #include "gtest/gtest.h" #include #include // We must define this macro in order to #include // gtest-internal-inl.h. This is how Google Test prevents a user from // accidentally depending on its internal implementation. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ #if GTEST_IS_THREADSAFE namespace testing { namespace { using internal::Notification; using internal::TestPropertyKeyIs; using internal::ThreadWithParam; using internal::scoped_ptr; // In order to run tests in this file, for platforms where Google Test is // thread safe, implement ThreadWithParam. See the description of its API // in gtest-port.h, where it is defined for already supported platforms. // How many threads to create? const int kThreadCount = 50; std::string IdToKey(int id, const char* suffix) { Message key; key << "key_" << id << "_" << suffix; return key.GetString(); } std::string IdToString(int id) { Message id_message; id_message << id; return id_message.GetString(); } void ExpectKeyAndValueWereRecordedForId( const std::vector& properties, int id, const char* suffix) { TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); const std::vector::const_iterator property = std::find_if(properties.begin(), properties.end(), matches_key); ASSERT_TRUE(property != properties.end()) << "expecting " << suffix << " value for id " << id; EXPECT_STREQ(IdToString(id).c_str(), property->value()); } // Calls a large number of Google Test assertions, where exactly one of them // will fail. void ManyAsserts(int id) { GTEST_LOG_(INFO) << "Thread #" << id << " running..."; SCOPED_TRACE(Message() << "Thread #" << id); for (int i = 0; i < kThreadCount; i++) { SCOPED_TRACE(Message() << "Iteration #" << i); // A bunch of assertions that should succeed. EXPECT_TRUE(true); ASSERT_FALSE(false) << "This shouldn't fail."; EXPECT_STREQ("a", "a"); ASSERT_LE(5, 6); EXPECT_EQ(i, i) << "This shouldn't fail."; // RecordProperty() should interact safely with other threads as well. // The shared_key forces property updates. Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str()); Test::RecordProperty(IdToKey(id, "int").c_str(), id); Test::RecordProperty("shared_key", IdToString(id).c_str()); // This assertion should fail kThreadCount times per thread. It // is for testing whether Google Test can handle failed assertions in a // multi-threaded context. EXPECT_LT(i, 0) << "This should always fail."; } } void CheckTestFailureCount(int expected_failures) { const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); const TestResult* const result = info->result(); GTEST_CHECK_(expected_failures == result->total_part_count()) << "Logged " << result->total_part_count() << " failures " << " vs. " << expected_failures << " expected"; } // Tests using SCOPED_TRACE() and Google Test assertions in many threads // concurrently. TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { { scoped_ptr > threads[kThreadCount]; Notification threads_can_start; for (int i = 0; i != kThreadCount; i++) threads[i].reset(new ThreadWithParam(&ManyAsserts, i, &threads_can_start)); threads_can_start.Notify(); // Blocks until all the threads are done. for (int i = 0; i != kThreadCount; i++) threads[i]->Join(); } // Ensures that kThreadCount*kThreadCount failures have been reported. const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); const TestResult* const result = info->result(); std::vector properties; // We have no access to the TestResult's list of properties but we can // copy them one by one. for (int i = 0; i < result->test_property_count(); ++i) properties.push_back(result->GetTestProperty(i)); EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count()) << "String and int values recorded on each thread, " << "as well as one shared_key"; for (int i = 0; i < kThreadCount; ++i) { ExpectKeyAndValueWereRecordedForId(properties, i, "string"); ExpectKeyAndValueWereRecordedForId(properties, i, "int"); } CheckTestFailureCount(kThreadCount*kThreadCount); } void FailingThread(bool is_fatal) { if (is_fatal) FAIL() << "Fatal failure in some other thread. " << "(This failure is expected.)"; else ADD_FAILURE() << "Non-fatal failure in some other thread. " << "(This failure is expected.)"; } void GenerateFatalFailureInAnotherThread(bool is_fatal) { ThreadWithParam thread(&FailingThread, is_fatal, NULL); thread.Join(); } TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) { EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); // We should only have one failure (the one from // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE // should succeed. CheckTestFailureCount(1); } void AssertNoFatalFailureIgnoresFailuresInOtherThreads() { ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); } TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads) { // Using a subroutine, to make sure, that the test continues. AssertNoFatalFailureIgnoresFailuresInOtherThreads(); // We should only have one failure (the one from // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE // should succeed. CheckTestFailureCount(1); } TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) { // This statement should fail, since the current thread doesn't generate a // fatal failure, only another one does. EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected"); CheckTestFailureCount(2); } TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) { // This statement should succeed, because failures in all threads are // considered. EXPECT_FATAL_FAILURE_ON_ALL_THREADS( GenerateFatalFailureInAnotherThread(true), "expected"); CheckTestFailureCount(0); // We need to add a failure, because main() checks that there are failures. // But when only this test is run, we shouldn't have any failures. ADD_FAILURE() << "This is an expected non-fatal failure."; } TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads) { // This statement should fail, since the current thread doesn't generate a // fatal failure, only another one does. EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false), "expected"); CheckTestFailureCount(2); } TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) { // This statement should succeed, because failures in all threads are // considered. EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( GenerateFatalFailureInAnotherThread(false), "expected"); CheckTestFailureCount(0); // We need to add a failure, because main() checks that there are failures, // But when only this test is run, we shouldn't have any failures. ADD_FAILURE() << "This is an expected non-fatal failure."; } } // namespace } // namespace testing int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); const int result = RUN_ALL_TESTS(); // Expected to fail. GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected"; printf("\nPASS\n"); return 0; } #else TEST(StressTest, DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) { } int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } #endif // GTEST_IS_THREADSAFE mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_test_utils.py000077500000000000000000000250741273231111400300400ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test utilities for Google C++ Testing Framework.""" __author__ = 'wan@google.com (Zhanyong Wan)' import atexit import os import shutil import sys import tempfile import unittest _test_module = unittest # Suppresses the 'Import not at the top of the file' lint complaint. # pylint: disable-msg=C6204 try: import subprocess _SUBPROCESS_MODULE_AVAILABLE = True except: import popen2 _SUBPROCESS_MODULE_AVAILABLE = False # pylint: enable-msg=C6204 GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' IS_WINDOWS = os.name == 'nt' IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] # The environment variable for specifying the path to the premature-exit file. PREMATURE_EXIT_FILE_ENV_VAR = 'TEST_PREMATURE_EXIT_FILE' environ = os.environ.copy() def SetEnvVar(env_var, value): """Sets/unsets an environment variable to a given value.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] # Here we expose a class from a particular module, depending on the # environment. The comment suppresses the 'Invalid variable name' lint # complaint. TestCase = _test_module.TestCase # pylint: disable-msg=C6409 # Initially maps a flag to its default value. After # _ParseAndStripGTestFlags() is called, maps a flag to its actual value. _flag_map = {'source_dir': os.path.dirname(sys.argv[0]), 'build_dir': os.path.dirname(sys.argv[0])} _gtest_flags_are_parsed = False def _ParseAndStripGTestFlags(argv): """Parses and strips Google Test flags from argv. This is idempotent.""" # Suppresses the lint complaint about a global variable since we need it # here to maintain module-wide state. global _gtest_flags_are_parsed # pylint: disable-msg=W0603 if _gtest_flags_are_parsed: return _gtest_flags_are_parsed = True for flag in _flag_map: # The environment variable overrides the default value. if flag.upper() in os.environ: _flag_map[flag] = os.environ[flag.upper()] # The command line flag overrides the environment variable. i = 1 # Skips the program name. while i < len(argv): prefix = '--' + flag + '=' if argv[i].startswith(prefix): _flag_map[flag] = argv[i][len(prefix):] del argv[i] break else: # We don't increment i in case we just found a --gtest_* flag # and removed it from argv. i += 1 def GetFlag(flag): """Returns the value of the given flag.""" # In case GetFlag() is called before Main(), we always call # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags # are parsed. _ParseAndStripGTestFlags(sys.argv) return _flag_map[flag] def GetSourceDir(): """Returns the absolute path of the directory where the .py files are.""" return os.path.abspath(GetFlag('source_dir')) def GetBuildDir(): """Returns the absolute path of the directory where the test binaries are.""" return os.path.abspath(GetFlag('build_dir')) _temp_dir = None def _RemoveTempDir(): if _temp_dir: shutil.rmtree(_temp_dir, ignore_errors=True) atexit.register(_RemoveTempDir) def GetTempDir(): """Returns a directory for temporary files.""" global _temp_dir if not _temp_dir: _temp_dir = tempfile.mkdtemp() return _temp_dir def GetTestExecutablePath(executable_name, build_dir=None): """Returns the absolute path of the test binary given its name. The function will print a message and abort the program if the resulting file doesn't exist. Args: executable_name: name of the test binary that the test script runs. build_dir: directory where to look for executables, by default the result of GetBuildDir(). Returns: The absolute path of the test binary. """ path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), executable_name)) if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'): path += '.exe' if not os.path.exists(path): message = ( 'Unable to find the test binary. Please make sure to provide path\n' 'to the binary via the --build_dir flag or the BUILD_DIR\n' 'environment variable.') print >> sys.stderr, message sys.exit(1) return path def GetExitStatus(exit_code): """Returns the argument to exit(), or -1 if exit() wasn't called. Args: exit_code: the result value of os.system(command). """ if os.name == 'nt': # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns # the argument to exit() directly. return exit_code else: # On Unix, os.WEXITSTATUS() must be used to extract the exit status # from the result of os.system(). if os.WIFEXITED(exit_code): return os.WEXITSTATUS(exit_code) else: return -1 class Subprocess: def __init__(self, command, working_dir=None, capture_stderr=True, env=None): """Changes into a specified directory, if provided, and executes a command. Restores the old directory afterwards. Args: command: The command to run, in the form of sys.argv. working_dir: The directory to change into. capture_stderr: Determines whether to capture stderr in the output member or to discard it. env: Dictionary with environment to pass to the subprocess. Returns: An object that represents outcome of the executed process. It has the following attributes: terminated_by_signal True iff the child process has been terminated by a signal. signal Sygnal that terminated the child process. exited True iff the child process exited normally. exit_code The code with which the child process exited. output Child process's stdout and stderr output combined in a string. """ # The subprocess module is the preferrable way of running programs # since it is available and behaves consistently on all platforms, # including Windows. But it is only available starting in python 2.4. # In earlier python versions, we revert to the popen2 module, which is # available in python 2.0 and later but doesn't provide required # functionality (Popen4) under Windows. This allows us to support Mac # OS X 10.4 Tiger, which has python 2.3 installed. if _SUBPROCESS_MODULE_AVAILABLE: if capture_stderr: stderr = subprocess.STDOUT else: stderr = subprocess.PIPE p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=stderr, cwd=working_dir, universal_newlines=True, env=env) # communicate returns a tuple with the file obect for the child's # output. self.output = p.communicate()[0] self._return_code = p.returncode else: old_dir = os.getcwd() def _ReplaceEnvDict(dest, src): # Changes made by os.environ.clear are not inheritable by child # processes until Python 2.6. To produce inheritable changes we have # to delete environment items with the del statement. for key in dest.keys(): del dest[key] dest.update(src) # When 'env' is not None, backup the environment variables and replace # them with the passed 'env'. When 'env' is None, we simply use the # current 'os.environ' for compatibility with the subprocess.Popen # semantics used above. if env is not None: old_environ = os.environ.copy() _ReplaceEnvDict(os.environ, env) try: if working_dir is not None: os.chdir(working_dir) if capture_stderr: p = popen2.Popen4(command) else: p = popen2.Popen3(command) p.tochild.close() self.output = p.fromchild.read() ret_code = p.wait() finally: os.chdir(old_dir) # Restore the old environment variables # if they were replaced. if env is not None: _ReplaceEnvDict(os.environ, old_environ) # Converts ret_code to match the semantics of # subprocess.Popen.returncode. if os.WIFSIGNALED(ret_code): self._return_code = -os.WTERMSIG(ret_code) else: # os.WIFEXITED(ret_code) should return True here. self._return_code = os.WEXITSTATUS(ret_code) if self._return_code < 0: self.terminated_by_signal = True self.exited = False self.signal = -self._return_code else: self.terminated_by_signal = False self.exited = True self.exit_code = self._return_code def Main(): """Runs the unit test.""" # We must call _ParseAndStripGTestFlags() before calling # unittest.main(). Otherwise the latter will be confused by the # --gtest_* flags. _ParseAndStripGTestFlags(sys.argv) # The tested binaries should not be writing XML output files unless the # script explicitly instructs them to. # TODO(vladl@google.com): Move this into Subprocess when we implement # passing environment into it as a parameter. if GTEST_OUTPUT_VAR_NAME in os.environ: del os.environ[GTEST_OUTPUT_VAR_NAME] _test_module.main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_throw_on_failure_ex_test.cc000066400000000000000000000065641273231111400326770ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Tests Google Test's throw-on-failure mode with exceptions enabled. #include "gtest/gtest.h" #include #include #include #include // Prints the given failure message and exits the program with // non-zero. We use this instead of a Google Test assertion to // indicate a failure, as the latter is been tested and cannot be // relied on. void Fail(const char* msg) { printf("FAILURE: %s\n", msg); fflush(stdout); exit(1); } // Tests that an assertion failure throws a subclass of // std::runtime_error. void TestFailureThrowsRuntimeError() { testing::GTEST_FLAG(throw_on_failure) = true; // A successful assertion shouldn't throw. try { EXPECT_EQ(3, 3); } catch(...) { Fail("A successful assertion wrongfully threw."); } // A failed assertion should throw a subclass of std::runtime_error. try { EXPECT_EQ(2, 3) << "Expected failure"; } catch(const std::runtime_error& e) { if (strstr(e.what(), "Expected failure") != NULL) return; printf("%s", "A failed assertion did throw an exception of the right type, " "but the message is incorrect. Instead of containing \"Expected " "failure\", it is:\n"); Fail(e.what()); } catch(...) { Fail("A failed assertion threw the wrong type of exception."); } Fail("A failed assertion should've thrown but didn't."); } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); // We want to ensure that people can use Google Test assertions in // other testing frameworks, as long as they initialize Google Test // properly and set the thrown-on-failure mode. Therefore, we don't // use Google Test's constructs for defining and running tests // (e.g. TEST and RUN_ALL_TESTS) here. TestFailureThrowsRuntimeError(); return 0; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_throw_on_failure_test.py000077500000000000000000000132061273231111400322400ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright 2009, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Tests Google Test's throw-on-failure mode with exceptions disabled. This script invokes gtest_throw_on_failure_test_ (a program written with Google Test) with different environments and command line flags. """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import gtest_test_utils # Constants. # The command line flag for enabling/disabling the throw-on-failure mode. THROW_ON_FAILURE = 'gtest_throw_on_failure' # Path to the gtest_throw_on_failure_test_ program, compiled with # exceptions disabled. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_throw_on_failure_test_') # Utilities. def SetEnvVar(env_var, value): """Sets an environment variable to a given value; unsets it when the given value is None. """ env_var = env_var.upper() if value is not None: os.environ[env_var] = value elif env_var in os.environ: del os.environ[env_var] def Run(command): """Runs a command; returns True/False if its exit code is/isn't 0.""" print 'Running "%s". . .' % ' '.join(command) p = gtest_test_utils.Subprocess(command) return p.exited and p.exit_code == 0 # The tests. TODO(wan@google.com): refactor the class to share common # logic with code in gtest_break_on_failure_unittest.py. class ThrowOnFailureTest(gtest_test_utils.TestCase): """Tests the throw-on-failure mode.""" def RunAndVerify(self, env_var_value, flag_value, should_fail): """Runs gtest_throw_on_failure_test_ and verifies that it does (or does not) exit with a non-zero code. Args: env_var_value: value of the GTEST_BREAK_ON_FAILURE environment variable; None if the variable should be unset. flag_value: value of the --gtest_break_on_failure flag; None if the flag should not be present. should_fail: True iff the program is expected to fail. """ SetEnvVar(THROW_ON_FAILURE, env_var_value) if env_var_value is None: env_var_value_msg = ' is not set' else: env_var_value_msg = '=' + env_var_value if flag_value is None: flag = '' elif flag_value == '0': flag = '--%s=0' % THROW_ON_FAILURE else: flag = '--%s' % THROW_ON_FAILURE command = [EXE_PATH] if flag: command.append(flag) if should_fail: should_or_not = 'should' else: should_or_not = 'should not' failed = not Run(command) SetEnvVar(THROW_ON_FAILURE, None) msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero ' 'exit code.' % (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command), should_or_not)) self.assert_(failed == should_fail, msg) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False) def testThrowOnFailureEnvVar(self): """Tests using the GTEST_THROW_ON_FAILURE environment variable.""" self.RunAndVerify(env_var_value='0', flag_value=None, should_fail=False) self.RunAndVerify(env_var_value='1', flag_value=None, should_fail=True) def testThrowOnFailureFlag(self): """Tests using the --gtest_throw_on_failure flag.""" self.RunAndVerify(env_var_value=None, flag_value='0', should_fail=False) self.RunAndVerify(env_var_value=None, flag_value='1', should_fail=True) def testThrowOnFailureFlagOverridesEnvVar(self): """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE.""" self.RunAndVerify(env_var_value='0', flag_value='0', should_fail=False) self.RunAndVerify(env_var_value='0', flag_value='1', should_fail=True) self.RunAndVerify(env_var_value='1', flag_value='0', should_fail=False) self.RunAndVerify(env_var_value='1', flag_value='1', should_fail=True) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_throw_on_failure_test_.cc000066400000000000000000000060401273231111400323270ustar00rootroot00000000000000// Copyright 2009, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Tests Google Test's throw-on-failure mode with exceptions disabled. // // This program must be compiled with exceptions disabled. It will be // invoked by gtest_throw_on_failure_test.py, and is expected to exit // with non-zero in the throw-on-failure mode or 0 otherwise. #include "gtest/gtest.h" #include // for fflush, fprintf, NULL, etc. #include // for exit #include // for set_terminate // This terminate handler aborts the program using exit() rather than abort(). // This avoids showing pop-ups on Windows systems and core dumps on Unix-like // ones. void TerminateHandler() { fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); fflush(NULL); exit(1); } int main(int argc, char** argv) { #if GTEST_HAS_EXCEPTIONS std::set_terminate(&TerminateHandler); #endif testing::InitGoogleTest(&argc, argv); // We want to ensure that people can use Google Test assertions in // other testing frameworks, as long as they initialize Google Test // properly and set the throw-on-failure mode. Therefore, we don't // use Google Test's constructs for defining and running tests // (e.g. TEST and RUN_ALL_TESTS) here. // In the throw-on-failure mode with exceptions disabled, this // assertion will cause the program to exit with a non-zero code. EXPECT_EQ(2, 3); // When not in the throw-on-failure mode, the control will reach // here. return 0; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_uninitialized_test.py000077500000000000000000000046601273231111400315460ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Verifies that Google Test warns the user when not initialized properly.""" __author__ = 'wan@google.com (Zhanyong Wan)' import gtest_test_utils COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_') def Assert(condition): if not condition: raise AssertionError def AssertEq(expected, actual): if expected != actual: print 'Expected: %s' % (expected,) print ' Actual: %s' % (actual,) raise AssertionError def TestExitCodeAndOutput(command): """Runs the given command and verifies its exit code and output.""" # Verifies that 'command' exits with code 1. p = gtest_test_utils.Subprocess(command) Assert(p.exited) AssertEq(1, p.exit_code) Assert('InitGoogleTest' in p.output) class GTestUninitializedTest(gtest_test_utils.TestCase): def testExitCodeAndOutput(self): TestExitCodeAndOutput(COMMAND) if __name__ == '__main__': gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_uninitialized_test_.cc000066400000000000000000000036011273231111400316310ustar00rootroot00000000000000// 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.h" TEST(DummyTest, Dummy) { // This test doesn't verify anything. We just need it to create a // realistic stage for testing the behavior of Google Test when // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being // called first. } int main() { return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_unittest.cc000066400000000000000000007231111273231111400274470ustar00rootroot00000000000000// 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) // // Tests for Google Test itself. This verifies that the basic constructs of // Google Test work. #include "gtest/gtest.h" // Verifies that the command line flag variables can be accessed // in code once has been #included. // Do not move it after other #includes. TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { bool dummy = testing::GTEST_FLAG(also_run_disabled_tests) || testing::GTEST_FLAG(break_on_failure) || testing::GTEST_FLAG(catch_exceptions) || testing::GTEST_FLAG(color) != "unknown" || testing::GTEST_FLAG(filter) != "unknown" || testing::GTEST_FLAG(list_tests) || testing::GTEST_FLAG(output) != "unknown" || testing::GTEST_FLAG(print_time) || testing::GTEST_FLAG(random_seed) || testing::GTEST_FLAG(repeat) > 0 || testing::GTEST_FLAG(show_internal_stack_frames) || testing::GTEST_FLAG(shuffle) || testing::GTEST_FLAG(stack_trace_depth) > 0 || testing::GTEST_FLAG(stream_result_to) != "unknown" || testing::GTEST_FLAG(throw_on_failure); EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused. } #include // For INT_MAX. #include #include #include #include #include #include #include "gtest/gtest-spi.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 GTEST_CAN_STREAM_RESULTS_ class StreamingListenerTest : public Test { public: class FakeSocketWriter : public StreamingListener::AbstractSocketWriter { public: // Sends a string to the socket. virtual void Send(const string& message) { output_ += message; } string output_; }; StreamingListenerTest() : fake_sock_writer_(new FakeSocketWriter), streamer_(fake_sock_writer_), test_info_obj_("FooTest", "Bar", NULL, NULL, 0, NULL) {} protected: string* output() { return &(fake_sock_writer_->output_); } FakeSocketWriter* const fake_sock_writer_; StreamingListener streamer_; UnitTest unit_test_; TestInfo test_info_obj_; // The name test_info_ was taken by testing::Test. }; TEST_F(StreamingListenerTest, OnTestProgramEnd) { *output() = ""; streamer_.OnTestProgramEnd(unit_test_); EXPECT_EQ("event=TestProgramEnd&passed=1\n", *output()); } TEST_F(StreamingListenerTest, OnTestIterationEnd) { *output() = ""; streamer_.OnTestIterationEnd(unit_test_, 42); EXPECT_EQ("event=TestIterationEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestCaseStart) { *output() = ""; streamer_.OnTestCaseStart(TestCase("FooTest", "Bar", NULL, NULL)); EXPECT_EQ("event=TestCaseStart&name=FooTest\n", *output()); } TEST_F(StreamingListenerTest, OnTestCaseEnd) { *output() = ""; streamer_.OnTestCaseEnd(TestCase("FooTest", "Bar", NULL, NULL)); EXPECT_EQ("event=TestCaseEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestStart) { *output() = ""; streamer_.OnTestStart(test_info_obj_); EXPECT_EQ("event=TestStart&name=Bar\n", *output()); } TEST_F(StreamingListenerTest, OnTestEnd) { *output() = ""; streamer_.OnTestEnd(test_info_obj_); EXPECT_EQ("event=TestEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestPartResult) { *output() = ""; streamer_.OnTestPartResult(TestPartResult( TestPartResult::kFatalFailure, "foo.cc", 42, "failed=\n&%")); // Meta characters in the failure message should be properly escaped. EXPECT_EQ( "event=TestPartResult&file=foo.cc&line=42&message=failed%3D%0A%26%25\n", *output()); } #endif // GTEST_CAN_STREAM_RESULTS_ // Provides access to otherwise private parts of the TestEventListeners class // that are needed to test it. class TestEventListenersAccessor { public: static TestEventListener* GetRepeater(TestEventListeners* listeners) { return listeners->repeater(); } static void SetDefaultResultPrinter(TestEventListeners* listeners, TestEventListener* listener) { listeners->SetDefaultResultPrinter(listener); } static void SetDefaultXmlGenerator(TestEventListeners* listeners, TestEventListener* listener) { listeners->SetDefaultXmlGenerator(listener); } static bool EventForwardingEnabled(const TestEventListeners& listeners) { return listeners.EventForwardingEnabled(); } static void SuppressEventForwarding(TestEventListeners* listeners) { listeners->SuppressEventForwarding(); } }; class UnitTestRecordPropertyTestHelper : public Test { protected: UnitTestRecordPropertyTestHelper() {} // Forwards to UnitTest::RecordProperty() to bypass access controls. void UnitTestRecordProperty(const char* key, const std::string& value) { unit_test_.RecordProperty(key, value); } UnitTest unit_test_; }; } // namespace internal } // namespace testing using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; using testing::DoubleLE; using testing::EmptyTestEventListener; using testing::Environment; using testing::FloatLE; using testing::GTEST_FLAG(also_run_disabled_tests); using testing::GTEST_FLAG(break_on_failure); using testing::GTEST_FLAG(catch_exceptions); using testing::GTEST_FLAG(color); using testing::GTEST_FLAG(death_test_use_fork); using testing::GTEST_FLAG(filter); using testing::GTEST_FLAG(list_tests); using testing::GTEST_FLAG(output); using testing::GTEST_FLAG(print_time); using testing::GTEST_FLAG(random_seed); using testing::GTEST_FLAG(repeat); using testing::GTEST_FLAG(show_internal_stack_frames); using testing::GTEST_FLAG(shuffle); using testing::GTEST_FLAG(stack_trace_depth); using testing::GTEST_FLAG(stream_result_to); using testing::GTEST_FLAG(throw_on_failure); using testing::IsNotSubstring; using testing::IsSubstring; using testing::Message; using testing::ScopedFakeTestPartResultReporter; using testing::StaticAssertTypeEq; using testing::Test; using testing::TestCase; using testing::TestEventListeners; using testing::TestInfo; using testing::TestPartResult; using testing::TestPartResultArray; using testing::TestProperty; using testing::TestResult; using testing::TimeInMillis; using testing::UnitTest; using testing::kMaxStackTraceDepth; using testing::internal::AddReference; using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; using testing::internal::AppendUserMessage; using testing::internal::ArrayAwareFind; using testing::internal::ArrayEq; using testing::internal::CodePointToUtf8; using testing::internal::CompileAssertTypesEqual; using testing::internal::CopyArray; using testing::internal::CountIf; using testing::internal::EqFailure; using testing::internal::FloatingPoint; using testing::internal::ForEach; using testing::internal::FormatEpochTimeInMillisAsIso8601; using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; using testing::internal::GetElementOr; using testing::internal::GetNextRandomSeed; using testing::internal::GetRandomSeedFromFlag; using testing::internal::GetTestTypeId; using testing::internal::GetTimeInMillis; using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; using testing::internal::ImplicitlyConvertible; using testing::internal::Int32; using testing::internal::Int32FromEnvOrDie; using testing::internal::IsAProtocolMessage; using testing::internal::IsContainer; using testing::internal::IsContainerTest; using testing::internal::IsNotContainer; using testing::internal::NativeArray; using testing::internal::ParseInt32Flag; using testing::internal::RemoveConst; using testing::internal::RemoveReference; using testing::internal::ShouldRunTestOnShard; using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; using testing::internal::Shuffle; using testing::internal::ShuffleRange; using testing::internal::SkipPrefix; using testing::internal::StreamableToString; using testing::internal::String; using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::UInt32; using testing::internal::WideStringToUtf8; using testing::internal::kCopy; using testing::internal::kMaxRandomSeed; using testing::internal::kReference; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; #if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; #endif #if GTEST_IS_THREADSAFE using testing::internal::ThreadWithParam; #endif class TestingVector : public std::vector { }; ::std::ostream& operator<<(::std::ostream& os, const TestingVector& vector) { os << "{ "; for (size_t i = 0; i < vector.size(); i++) { os << vector[i] << " "; } os << "}"; return os; } // This line tests that we can define tests in an unnamed namespace. namespace { TEST(GetRandomSeedFromFlagTest, HandlesZero) { const int seed = GetRandomSeedFromFlag(0); EXPECT_LE(1, seed); EXPECT_LE(seed, static_cast(kMaxRandomSeed)); } TEST(GetRandomSeedFromFlagTest, PreservesValidSeed) { EXPECT_EQ(1, GetRandomSeedFromFlag(1)); EXPECT_EQ(2, GetRandomSeedFromFlag(2)); EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1)); EXPECT_EQ(static_cast(kMaxRandomSeed), GetRandomSeedFromFlag(kMaxRandomSeed)); } TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) { const int seed1 = GetRandomSeedFromFlag(-1); EXPECT_LE(1, seed1); EXPECT_LE(seed1, static_cast(kMaxRandomSeed)); const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1); EXPECT_LE(1, seed2); EXPECT_LE(seed2, static_cast(kMaxRandomSeed)); } TEST(GetNextRandomSeedTest, WorksForValidInput) { EXPECT_EQ(2, GetNextRandomSeed(1)); EXPECT_EQ(3, GetNextRandomSeed(2)); EXPECT_EQ(static_cast(kMaxRandomSeed), GetNextRandomSeed(kMaxRandomSeed - 1)); EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed)); // We deliberately don't test GetNextRandomSeed() with invalid // inputs, as that requires death tests, which are expensive. This // is fine as GetNextRandomSeed() is internal and has a // straightforward definition. } static void ClearCurrentTestPartResults() { TestResultAccessor::ClearTestPartResults( GetUnitTestImpl()->current_test_result()); } // Tests GetTypeId. TEST(GetTypeIdTest, ReturnsSameValueForSameType) { EXPECT_EQ(GetTypeId(), GetTypeId()); EXPECT_EQ(GetTypeId(), GetTypeId()); } class SubClassOfTest : public Test {}; class AnotherSubClassOfTest : public Test {}; TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) { EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); } // Verifies that GetTestTypeId() returns the same value, no matter it // is called from inside Google Test or outside of it. TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest) { EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId()); } // Tests FormatTimeInMillisAsSeconds(). TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) { EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0)); } TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) { EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3)); EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10)); EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200)); EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200)); EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000)); } TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) { EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3)); EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10)); EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200)); EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200)); EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000)); } // Tests FormatEpochTimeInMillisAsIso8601(). The correctness of conversion // for particular dates below was verified in Python using // datetime.datetime.fromutctimestamp(/1000). // FormatEpochTimeInMillisAsIso8601 depends on the current timezone, so we // have to set up a particular timezone to obtain predictable results. class FormatEpochTimeInMillisAsIso8601Test : public Test { public: // On Cygwin, GCC doesn't allow unqualified integer literals to exceed // 32 bits, even when 64-bit integer types are available. We have to // force the constants to have a 64-bit type here. static const TimeInMillis kMillisPerSec = 1000; private: virtual void SetUp() { saved_tz_ = NULL; #if _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function or variable may be unsafe // for getenv, function is deprecated for // strdup). if (getenv("TZ")) saved_tz_ = strdup(getenv("TZ")); # pragma warning(pop) // Restores the warning state again. #else if (getenv("TZ")) saved_tz_ = strdup(getenv("TZ")); #endif // Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We // cannot use the local time zone because the function's output depends // on the time zone. SetTimeZone("UTC+00"); } virtual void TearDown() { SetTimeZone(saved_tz_); free(const_cast(saved_tz_)); saved_tz_ = NULL; } static void SetTimeZone(const char* time_zone) { // tzset() distinguishes between the TZ variable being present and empty // and not being present, so we have to consider the case of time_zone // being NULL. #if _MSC_VER // ...Unless it's MSVC, whose standard library's _putenv doesn't // distinguish between an empty and a missing variable. const std::string env_var = std::string("TZ=") + (time_zone ? time_zone : ""); _putenv(env_var.c_str()); # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function is deprecated). tzset(); # pragma warning(pop) // Restores the warning state again. #else if (time_zone) { setenv(("TZ"), time_zone, 1); } else { unsetenv("TZ"); } tzset(); #endif } const char* saved_tz_; }; const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec; TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments) { EXPECT_EQ("2011-10-31T18:52:42", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult) { EXPECT_EQ( "2011-10-31T18:52:42", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes) { EXPECT_EQ("2011-09-03T05:07:02", FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime) { EXPECT_EQ("2011-09-28T17:08:22", FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) { EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0)); } #if GTEST_CAN_COMPARE_NULL # ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" # pragma option push -w-ccc -w-rch # endif // Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null // pointer literal. TEST(NullLiteralTest, IsTrueForNullLiterals) { EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0U)); EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0L)); } // Tests that GTEST_IS_NULL_LITERAL_(x) is false when x is not a null // pointer literal. TEST(NullLiteralTest, IsFalseForNonNullLiterals) { EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(1)); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(0.0)); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_('a')); EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast(NULL))); } # ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" suppressed them. # pragma option pop # endif #endif // GTEST_CAN_COMPARE_NULL // // Tests CodePointToUtf8(). // Tests that the NUL character L'\0' is encoded correctly. TEST(CodePointToUtf8Test, CanEncodeNul) { EXPECT_EQ("", CodePointToUtf8(L'\0')); } // Tests that ASCII characters are encoded correctly. TEST(CodePointToUtf8Test, CanEncodeAscii) { EXPECT_EQ("a", CodePointToUtf8(L'a')); EXPECT_EQ("Z", CodePointToUtf8(L'Z')); EXPECT_EQ("&", CodePointToUtf8(L'&')); EXPECT_EQ("\x7F", CodePointToUtf8(L'\x7F')); } // Tests that Unicode code-points that have 8 to 11 bits are encoded // as 110xxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode8To11Bits) { // 000 1101 0011 => 110-00011 10-010011 EXPECT_EQ("\xC3\x93", CodePointToUtf8(L'\xD3')); // 101 0111 0110 => 110-10101 10-110110 // Some compilers (e.g., GCC on MinGW) cannot handle non-ASCII codepoints // in wide strings and wide chars. In order to accomodate them, we have to // introduce such character constants as integers. EXPECT_EQ("\xD5\xB6", CodePointToUtf8(static_cast(0x576))); } // Tests that Unicode code-points that have 12 to 16 bits are encoded // as 1110xxxx 10xxxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode12To16Bits) { // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 EXPECT_EQ("\xE0\xA3\x93", CodePointToUtf8(static_cast(0x8D3))); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 EXPECT_EQ("\xEC\x9D\x8D", CodePointToUtf8(static_cast(0xC74D))); } #if !GTEST_WIDE_STRING_USES_UTF16_ // Tests in this group require a wchar_t to hold > 16 bits, and thus // are skipped on Windows, Cygwin, and Symbian, where a wchar_t is // 16-bit wide. This code may not compile on those systems. // Tests that Unicode code-points that have 17 to 21 bits are encoded // as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode17To21Bits) { // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 EXPECT_EQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3')); // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000 EXPECT_EQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400')); // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 EXPECT_EQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634')); } // Tests that encoding an invalid code-point generates the expected result. TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) { EXPECT_EQ("(Invalid Unicode 0x1234ABCD)", CodePointToUtf8(L'\x1234ABCD')); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests WideStringToUtf8(). // Tests that the NUL character L'\0' is encoded correctly. TEST(WideStringToUtf8Test, CanEncodeNul) { EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str()); EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str()); } // Tests that ASCII strings are encoded correctly. TEST(WideStringToUtf8Test, CanEncodeAscii) { EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str()); EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str()); EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str()); EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str()); } // Tests that Unicode code-points that have 8 to 11 bits are encoded // as 110xxxxx 10xxxxxx. TEST(WideStringToUtf8Test, CanEncode8To11Bits) { // 000 1101 0011 => 110-00011 10-010011 EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str()); EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str()); // 101 0111 0110 => 110-10101 10-110110 const wchar_t s[] = { 0x576, '\0' }; EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, 1).c_str()); EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, -1).c_str()); } // Tests that Unicode code-points that have 12 to 16 bits are encoded // as 1110xxxx 10xxxxxx 10xxxxxx. TEST(WideStringToUtf8Test, CanEncode12To16Bits) { // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 const wchar_t s1[] = { 0x8D3, '\0' }; EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, 1).c_str()); EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, -1).c_str()); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 const wchar_t s2[] = { 0xC74D, '\0' }; EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, 1).c_str()); EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, -1).c_str()); } // Tests that the conversion stops when the function encounters \0 character. TEST(WideStringToUtf8Test, StopsOnNulCharacter) { EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str()); } // Tests that the conversion stops when the function reaches the limit // specified by the 'length' parameter. TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached) { EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str()); } #if !GTEST_WIDE_STRING_USES_UTF16_ // Tests that Unicode code-points that have 17 to 21 bits are encoded // as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile // on the systems using UTF-16 encoding. TEST(WideStringToUtf8Test, CanEncode17To21Bits) { // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str()); EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str()); // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str()); EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str()); } // Tests that encoding an invalid code-point generates the expected result. TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint) { EXPECT_STREQ("(Invalid Unicode 0xABCDFF)", WideStringToUtf8(L"\xABCDFF", -1).c_str()); } #else // !GTEST_WIDE_STRING_USES_UTF16_ // Tests that surrogate pairs are encoded correctly on the systems using // UTF-16 encoding in the wide strings. TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs) { const wchar_t s[] = { 0xD801, 0xDC00, '\0' }; EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(s, -1).c_str()); } // Tests that encoding an invalid UTF-16 surrogate pair // generates the expected result. TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair) { // Leading surrogate is at the end of the string. const wchar_t s1[] = { 0xD800, '\0' }; EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(s1, -1).c_str()); // Leading surrogate is not followed by the trailing surrogate. const wchar_t s2[] = { 0xD800, 'M', '\0' }; EXPECT_STREQ("\xED\xA0\x80M", WideStringToUtf8(s2, -1).c_str()); // Trailing surrogate appearas without a leading surrogate. const wchar_t s3[] = { 0xDC00, 'P', 'Q', 'R', '\0' }; EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(s3, -1).c_str()); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests that codepoint concatenation works correctly. #if !GTEST_WIDE_STRING_USES_UTF16_ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { const wchar_t s[] = { 0x108634, 0xC74D, '\n', 0x576, 0x8D3, 0x108634, '\0'}; EXPECT_STREQ( "\xF4\x88\x98\xB4" "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93" "\xF4\x88\x98\xB4", WideStringToUtf8(s, -1).c_str()); } #else TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { const wchar_t s[] = { 0xC74D, '\n', 0x576, 0x8D3, '\0'}; EXPECT_STREQ( "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93", WideStringToUtf8(s, -1).c_str()); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests the Random class. TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) { testing::internal::Random random(42); EXPECT_DEATH_IF_SUPPORTED( random.Generate(0), "Cannot generate a number in the range \\[0, 0\\)"); EXPECT_DEATH_IF_SUPPORTED( random.Generate(testing::internal::Random::kMaxRange + 1), "Generation of a number in \\[0, 2147483649\\) was requested, " "but this can only generate numbers in \\[0, 2147483648\\)"); } TEST(RandomTest, GeneratesNumbersWithinRange) { const UInt32 kRange = 10000; testing::internal::Random random(12345); for (int i = 0; i < 10; i++) { EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i; } testing::internal::Random random2(testing::internal::Random::kMaxRange); for (int i = 0; i < 10; i++) { EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i; } } TEST(RandomTest, RepeatsWhenReseeded) { const int kSeed = 123; const int kArraySize = 10; const UInt32 kRange = 10000; UInt32 values[kArraySize]; testing::internal::Random random(kSeed); for (int i = 0; i < kArraySize; i++) { values[i] = random.Generate(kRange); } random.Reseed(kSeed); for (int i = 0; i < kArraySize; i++) { EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i; } } // Tests STL container utilities. // Tests CountIf(). static bool IsPositive(int n) { return n > 0; } TEST(ContainerUtilityTest, CountIf) { std::vector v; EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container. v.push_back(-1); v.push_back(0); EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies. v.push_back(2); v.push_back(-10); v.push_back(10); EXPECT_EQ(2, CountIf(v, IsPositive)); } // Tests ForEach(). static int g_sum = 0; static void Accumulate(int n) { g_sum += n; } TEST(ContainerUtilityTest, ForEach) { std::vector v; g_sum = 0; ForEach(v, Accumulate); EXPECT_EQ(0, g_sum); // Works for an empty container; g_sum = 0; v.push_back(1); ForEach(v, Accumulate); EXPECT_EQ(1, g_sum); // Works for a container with one element. g_sum = 0; v.push_back(20); v.push_back(300); ForEach(v, Accumulate); EXPECT_EQ(321, g_sum); } // Tests GetElementOr(). TEST(ContainerUtilityTest, GetElementOr) { std::vector a; EXPECT_EQ('x', GetElementOr(a, 0, 'x')); a.push_back('a'); a.push_back('b'); EXPECT_EQ('a', GetElementOr(a, 0, 'x')); EXPECT_EQ('b', GetElementOr(a, 1, 'x')); EXPECT_EQ('x', GetElementOr(a, -2, 'x')); EXPECT_EQ('x', GetElementOr(a, 2, 'x')); } TEST(ContainerUtilityDeathTest, ShuffleRange) { std::vector a; a.push_back(0); a.push_back(1); a.push_back(2); testing::internal::Random random(1); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, -1, 1, &a), "Invalid shuffle range start -1: must be in range \\[0, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 4, 4, &a), "Invalid shuffle range start 4: must be in range \\[0, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 3, 2, &a), "Invalid shuffle range finish 2: must be in range \\[3, 3\\]"); EXPECT_DEATH_IF_SUPPORTED( ShuffleRange(&random, 3, 4, &a), "Invalid shuffle range finish 4: must be in range \\[3, 3\\]"); } class VectorShuffleTest : public Test { protected: static const int kVectorSize = 20; VectorShuffleTest() : random_(1) { for (int i = 0; i < kVectorSize; i++) { vector_.push_back(i); } } static bool VectorIsCorrupt(const TestingVector& vector) { if (kVectorSize != static_cast(vector.size())) { return true; } bool found_in_vector[kVectorSize] = { false }; for (size_t i = 0; i < vector.size(); i++) { const int e = vector[i]; if (e < 0 || e >= kVectorSize || found_in_vector[e]) { return true; } found_in_vector[e] = true; } // Vector size is correct, elements' range is correct, no // duplicate elements. Therefore no corruption has occurred. return false; } static bool VectorIsNotCorrupt(const TestingVector& vector) { return !VectorIsCorrupt(vector); } static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) { for (int i = begin; i < end; i++) { if (i != vector[i]) { return true; } } return false; } static bool RangeIsUnshuffled( const TestingVector& vector, int begin, int end) { return !RangeIsShuffled(vector, begin, end); } static bool VectorIsShuffled(const TestingVector& vector) { return RangeIsShuffled(vector, 0, static_cast(vector.size())); } static bool VectorIsUnshuffled(const TestingVector& vector) { return !VectorIsShuffled(vector); } testing::internal::Random random_; TestingVector vector_; }; // class VectorShuffleTest const int VectorShuffleTest::kVectorSize; TEST_F(VectorShuffleTest, HandlesEmptyRange) { // Tests an empty range at the beginning... ShuffleRange(&random_, 0, 0, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...in the middle... ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...at the end... ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...and past the end. ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); } TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) { // Tests a size one range at the beginning... ShuffleRange(&random_, 0, 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...in the middle... ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); // ...and at the end. ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsUnshuffled, vector_); } // Because we use our own random number generator and a fixed seed, // we can guarantee that the following "random" tests will succeed. TEST_F(VectorShuffleTest, ShufflesEntireVector) { Shuffle(&random_, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_; // Tests the first and last elements in particular to ensure that // there are no off-by-one problems in our shuffle algorithm. EXPECT_NE(0, vector_[0]); EXPECT_NE(kVectorSize - 1, vector_[kVectorSize - 1]); } TEST_F(VectorShuffleTest, ShufflesStartOfVector) { const int kRangeSize = kVectorSize/2; ShuffleRange(&random_, 0, kRangeSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesEndOfVector) { const int kRangeSize = kVectorSize / 2; ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) { int kRangeSize = kVectorSize/3; ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector_); EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize); EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize); } TEST_F(VectorShuffleTest, ShufflesRepeatably) { TestingVector vector2; for (int i = 0; i < kVectorSize; i++) { vector2.push_back(i); } random_.Reseed(1234); Shuffle(&random_, &vector_); random_.Reseed(1234); Shuffle(&random_, &vector2); ASSERT_PRED1(VectorIsNotCorrupt, vector_); ASSERT_PRED1(VectorIsNotCorrupt, vector2); for (int i = 0; i < kVectorSize; i++) { EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i; } } // Tests the size of the AssertHelper class. TEST(AssertHelperTest, AssertHelperIsSmall) { // To avoid breaking clients that use lots of assertions in one // function, we cannot grow the size of AssertHelper. EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); } // Tests String::EndsWithCaseInsensitive(). TEST(StringTest, EndsWithCaseInsensitive) { EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "BAR")); EXPECT_TRUE(String::EndsWithCaseInsensitive("foobaR", "bar")); EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "")); EXPECT_TRUE(String::EndsWithCaseInsensitive("", "")); EXPECT_FALSE(String::EndsWithCaseInsensitive("Foobar", "foo")); EXPECT_FALSE(String::EndsWithCaseInsensitive("foobar", "Foo")); EXPECT_FALSE(String::EndsWithCaseInsensitive("", "foo")); } // C++Builder's preprocessor is buggy; it fails to expand macros that // appear in macro parameters after wide char literals. Provide an alias // for NULL as a workaround. static const wchar_t* const kNull = NULL; // Tests String::CaseInsensitiveWideCStringEquals TEST(StringTest, CaseInsensitiveWideCStringEquals) { EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL)); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"")); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull)); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar")); EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull)); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar")); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR")); EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar")); } #if GTEST_OS_WINDOWS // Tests String::ShowWideCString(). TEST(StringTest, ShowWideCString) { EXPECT_STREQ("(null)", String::ShowWideCString(NULL).c_str()); EXPECT_STREQ("", String::ShowWideCString(L"").c_str()); EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str()); } # if GTEST_OS_WINDOWS_MOBILE TEST(StringTest, AnsiAndUtf16Null) { EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); } TEST(StringTest, AnsiAndUtf16ConvertBasic) { const char* ansi = String::Utf16ToAnsi(L"str"); EXPECT_STREQ("str", ansi); delete [] ansi; const WCHAR* utf16 = String::AnsiToUtf16("str"); EXPECT_EQ(0, wcsncmp(L"str", utf16, 3)); delete [] utf16; } TEST(StringTest, AnsiAndUtf16ConvertPathChars) { const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?"); EXPECT_STREQ(".:\\ \"*?", ansi); delete [] ansi; const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?"); EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3)); delete [] utf16; } # endif // GTEST_OS_WINDOWS_MOBILE #endif // GTEST_OS_WINDOWS // Tests TestProperty construction. TEST(TestPropertyTest, StringValue) { TestProperty property("key", "1"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("1", property.value()); } // Tests TestProperty replacing a value. TEST(TestPropertyTest, ReplaceStringValue) { TestProperty property("key", "1"); EXPECT_STREQ("1", property.value()); property.SetValue("2"); EXPECT_STREQ("2", property.value()); } // AddFatalFailure() and AddNonfatalFailure() must be stand-alone // functions (i.e. their definitions cannot be inlined at the call // sites), or C++Builder won't compile the code. static void AddFatalFailure() { FAIL() << "Expected fatal failure."; } static void AddNonfatalFailure() { ADD_FAILURE() << "Expected non-fatal failure."; } class ScopedFakeTestPartResultReporterTest : public Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. enum FailureMode { FATAL_FAILURE, NONFATAL_FAILURE }; static void AddFailure(FailureMode failure) { if (failure == FATAL_FAILURE) { AddFatalFailure(); } else { AddNonfatalFailure(); } } }; // Tests that ScopedFakeTestPartResultReporter intercepts test // failures. TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures) { TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, &results); AddFailure(NONFATAL_FAILURE); AddFailure(FATAL_FAILURE); } EXPECT_EQ(2, results.size()); EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); } TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) { TestPartResultArray results; { // Tests, that the deprecated constructor still works. ScopedFakeTestPartResultReporter reporter(&results); AddFailure(NONFATAL_FAILURE); } EXPECT_EQ(1, results.size()); } #if GTEST_IS_THREADSAFE class ScopedFakeTestPartResultReporterWithThreadsTest : public ScopedFakeTestPartResultReporterTest { protected: static void AddFailureInOtherThread(FailureMode failure) { ThreadWithParam thread(&AddFailure, failure, NULL); thread.Join(); } }; TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest, InterceptsTestFailuresInAllThreads) { TestPartResultArray results; { ScopedFakeTestPartResultReporter reporter( ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results); AddFailure(NONFATAL_FAILURE); AddFailure(FATAL_FAILURE); AddFailureInOtherThread(NONFATAL_FAILURE); AddFailureInOtherThread(FATAL_FAILURE); } EXPECT_EQ(4, results.size()); EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed()); EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); } #endif // GTEST_IS_THREADSAFE // Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they // work even if the failure is generated in a called function rather than // the current context. typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest; TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure) { EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure."); } #if GTEST_HAS_GLOBAL_STRING TEST_F(ExpectFatalFailureTest, AcceptsStringObject) { EXPECT_FATAL_FAILURE(AddFatalFailure(), ::string("Expected fatal failure.")); } #endif TEST_F(ExpectFatalFailureTest, AcceptsStdStringObject) { EXPECT_FATAL_FAILURE(AddFatalFailure(), ::std::string("Expected fatal failure.")); } TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads) { // We have another test below to verify that the macro catches fatal // failures generated on another thread. EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(), "Expected fatal failure."); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true" # pragma option push -w-ccc #endif // Tests that EXPECT_FATAL_FAILURE() can be used in a non-void // function even when the statement in it contains ASSERT_*. int NonVoidFunction() { EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); return 0; } TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction) { NonVoidFunction(); } // Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the // current function even though 'statement' generates a fatal failure. void DoesNotAbortHelper(bool* aborted) { EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); *aborted = false; } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" suppressed them. # pragma option pop #endif TEST_F(ExpectFatalFailureTest, DoesNotAbort) { bool aborted = true; DoesNotAbortHelper(&aborted); EXPECT_FALSE(aborted); } // Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a // statement that contains a macro which expands to code containing an // unprotected comma. static int global_var = 0; #define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++ TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { #ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE({ GTEST_USE_UNPROTECTED_COMMA_; AddFatalFailure(); }, ""); #endif EXPECT_FATAL_FAILURE_ON_ALL_THREADS({ GTEST_USE_UNPROTECTED_COMMA_; AddFatalFailure(); }, ""); } // Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}. typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest; TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), "Expected non-fatal failure."); } #if GTEST_HAS_GLOBAL_STRING TEST_F(ExpectNonfatalFailureTest, AcceptsStringObject) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), ::string("Expected non-fatal failure.")); } #endif TEST_F(ExpectNonfatalFailureTest, AcceptsStdStringObject) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), ::std::string("Expected non-fatal failure.")); } TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads) { // We have another test below to verify that the macro catches // non-fatal failures generated on another thread. EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(), "Expected non-fatal failure."); } // Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a // statement that contains a macro which expands to code containing an // unprotected comma. TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { EXPECT_NONFATAL_FAILURE({ GTEST_USE_UNPROTECTED_COMMA_; AddNonfatalFailure(); }, ""); EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({ GTEST_USE_UNPROTECTED_COMMA_; AddNonfatalFailure(); }, ""); } #if GTEST_IS_THREADSAFE typedef ScopedFakeTestPartResultReporterWithThreadsTest ExpectFailureWithThreadsTest; TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads) { EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE), "Expected fatal failure."); } TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) { EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); } #endif // GTEST_IS_THREADSAFE // Tests the TestProperty class. TEST(TestPropertyTest, ConstructorWorks) { const TestProperty property("key", "value"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value", property.value()); } TEST(TestPropertyTest, SetValue) { TestProperty property("key", "value_1"); EXPECT_STREQ("key", property.key()); property.SetValue("value_2"); EXPECT_STREQ("key", property.key()); EXPECT_STREQ("value_2", property.value()); } // Tests the TestResult class // The test fixture for testing TestResult. class TestResultTest : public Test { protected: typedef std::vector TPRVector; // We make use of 2 TestPartResult objects, TestPartResult * pr1, * pr2; // ... and 3 TestResult objects. TestResult * r0, * r1, * r2; virtual void SetUp() { // pr1 is for success. pr1 = new TestPartResult(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"); // pr2 is for fatal failure. pr2 = new TestPartResult(TestPartResult::kFatalFailure, "foo/bar.cc", -1, // This line number means "unknown" "Failure!"); // Creates the TestResult objects. r0 = new TestResult(); r1 = new TestResult(); r2 = new TestResult(); // In order to test TestResult, we need to modify its internal // state, in particular the TestPartResult vector it holds. // test_part_results() returns a const reference to this vector. // We cast it to a non-const object s.t. it can be modified (yes, // this is a hack). TPRVector* results1 = const_cast( &TestResultAccessor::test_part_results(*r1)); TPRVector* results2 = const_cast( &TestResultAccessor::test_part_results(*r2)); // r0 is an empty TestResult. // r1 contains a single SUCCESS TestPartResult. results1->push_back(*pr1); // r2 contains a SUCCESS, and a FAILURE. results2->push_back(*pr1); results2->push_back(*pr2); } virtual void TearDown() { delete pr1; delete pr2; delete r0; delete r1; delete r2; } // Helper that compares two two TestPartResults. static void CompareTestPartResult(const TestPartResult& expected, const TestPartResult& actual) { EXPECT_EQ(expected.type(), actual.type()); EXPECT_STREQ(expected.file_name(), actual.file_name()); EXPECT_EQ(expected.line_number(), actual.line_number()); EXPECT_STREQ(expected.summary(), actual.summary()); EXPECT_STREQ(expected.message(), actual.message()); EXPECT_EQ(expected.passed(), actual.passed()); EXPECT_EQ(expected.failed(), actual.failed()); EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed()); EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed()); } }; // Tests TestResult::total_part_count(). TEST_F(TestResultTest, total_part_count) { ASSERT_EQ(0, r0->total_part_count()); ASSERT_EQ(1, r1->total_part_count()); ASSERT_EQ(2, r2->total_part_count()); } // Tests TestResult::Passed(). TEST_F(TestResultTest, Passed) { ASSERT_TRUE(r0->Passed()); ASSERT_TRUE(r1->Passed()); ASSERT_FALSE(r2->Passed()); } // Tests TestResult::Failed(). TEST_F(TestResultTest, Failed) { ASSERT_FALSE(r0->Failed()); ASSERT_FALSE(r1->Failed()); ASSERT_TRUE(r2->Failed()); } // Tests TestResult::GetTestPartResult(). typedef TestResultTest TestResultDeathTest; TEST_F(TestResultDeathTest, GetTestPartResult) { CompareTestPartResult(*pr1, r2->GetTestPartResult(0)); CompareTestPartResult(*pr2, r2->GetTestPartResult(1)); EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), ""); EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), ""); } // Tests TestResult has no properties when none are added. TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) { TestResult test_result; ASSERT_EQ(0, test_result.test_property_count()); } // Tests TestResult has the expected property when added. TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) { TestResult test_result; TestProperty property("key_1", "1"); TestResultAccessor::RecordProperty(&test_result, "testcase", property); ASSERT_EQ(1, test_result.test_property_count()); const TestProperty& actual_property = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property.key()); EXPECT_STREQ("1", actual_property.value()); } // Tests TestResult has multiple properties when added. TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) { TestResult test_result; TestProperty property_1("key_1", "1"); TestProperty property_2("key_2", "2"); TestResultAccessor::RecordProperty(&test_result, "testcase", property_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2); ASSERT_EQ(2, test_result.test_property_count()); const TestProperty& actual_property_1 = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property_1.key()); EXPECT_STREQ("1", actual_property_1.value()); const TestProperty& actual_property_2 = test_result.GetTestProperty(1); EXPECT_STREQ("key_2", actual_property_2.key()); EXPECT_STREQ("2", actual_property_2.value()); } // Tests TestResult::RecordProperty() overrides values for duplicate keys. TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) { TestResult test_result; TestProperty property_1_1("key_1", "1"); TestProperty property_2_1("key_2", "2"); TestProperty property_1_2("key_1", "12"); TestProperty property_2_2("key_2", "22"); TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_2); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_2); ASSERT_EQ(2, test_result.test_property_count()); const TestProperty& actual_property_1 = test_result.GetTestProperty(0); EXPECT_STREQ("key_1", actual_property_1.key()); EXPECT_STREQ("12", actual_property_1.value()); const TestProperty& actual_property_2 = test_result.GetTestProperty(1); EXPECT_STREQ("key_2", actual_property_2.key()); EXPECT_STREQ("22", actual_property_2.value()); } // Tests TestResult::GetTestProperty(). TEST(TestResultPropertyTest, GetTestProperty) { TestResult test_result; TestProperty property_1("key_1", "1"); TestProperty property_2("key_2", "2"); TestProperty property_3("key_3", "3"); TestResultAccessor::RecordProperty(&test_result, "testcase", property_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2); TestResultAccessor::RecordProperty(&test_result, "testcase", property_3); const TestProperty& fetched_property_1 = test_result.GetTestProperty(0); const TestProperty& fetched_property_2 = test_result.GetTestProperty(1); const TestProperty& fetched_property_3 = test_result.GetTestProperty(2); EXPECT_STREQ("key_1", fetched_property_1.key()); EXPECT_STREQ("1", fetched_property_1.value()); EXPECT_STREQ("key_2", fetched_property_2.key()); EXPECT_STREQ("2", fetched_property_2.value()); EXPECT_STREQ("key_3", fetched_property_3.key()); EXPECT_STREQ("3", fetched_property_3.value()); EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), ""); EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), ""); } // Tests that GTestFlagSaver works on Windows and Mac. class GTestFlagSaverTest : public Test { protected: // Saves the Google Test flags such that we can restore them later, and // then sets them to their default values. This will be called // before the first test in this test case is run. static void SetUpTestCase() { saver_ = new GTestFlagSaver; GTEST_FLAG(also_run_disabled_tests) = false; GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(color) = "auto"; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; GTEST_FLAG(output) = ""; GTEST_FLAG(print_time) = true; GTEST_FLAG(random_seed) = 0; GTEST_FLAG(repeat) = 1; GTEST_FLAG(shuffle) = false; GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; GTEST_FLAG(stream_result_to) = ""; GTEST_FLAG(throw_on_failure) = false; } // Restores the Google Test flags that the tests have modified. This will // be called after the last test in this test case is run. static void TearDownTestCase() { delete saver_; saver_ = NULL; } // Verifies that the Google Test flags have their default values, and then // modifies each of them. void VerifyAndModifyFlags() { EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests)); EXPECT_FALSE(GTEST_FLAG(break_on_failure)); EXPECT_FALSE(GTEST_FLAG(catch_exceptions)); EXPECT_STREQ("auto", GTEST_FLAG(color).c_str()); EXPECT_FALSE(GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ("", GTEST_FLAG(filter).c_str()); EXPECT_FALSE(GTEST_FLAG(list_tests)); EXPECT_STREQ("", GTEST_FLAG(output).c_str()); EXPECT_TRUE(GTEST_FLAG(print_time)); EXPECT_EQ(0, GTEST_FLAG(random_seed)); EXPECT_EQ(1, GTEST_FLAG(repeat)); EXPECT_FALSE(GTEST_FLAG(shuffle)); EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth)); EXPECT_STREQ("", GTEST_FLAG(stream_result_to).c_str()); EXPECT_FALSE(GTEST_FLAG(throw_on_failure)); GTEST_FLAG(also_run_disabled_tests) = true; GTEST_FLAG(break_on_failure) = true; GTEST_FLAG(catch_exceptions) = true; GTEST_FLAG(color) = "no"; GTEST_FLAG(death_test_use_fork) = true; GTEST_FLAG(filter) = "abc"; GTEST_FLAG(list_tests) = true; GTEST_FLAG(output) = "xml:foo.xml"; GTEST_FLAG(print_time) = false; GTEST_FLAG(random_seed) = 1; GTEST_FLAG(repeat) = 100; GTEST_FLAG(shuffle) = true; GTEST_FLAG(stack_trace_depth) = 1; GTEST_FLAG(stream_result_to) = "localhost:1234"; GTEST_FLAG(throw_on_failure) = true; } private: // For saving Google Test flags during this test case. static GTestFlagSaver* saver_; }; GTestFlagSaver* GTestFlagSaverTest::saver_ = NULL; // Google Test doesn't guarantee the order of tests. The following two // tests are designed to work regardless of their order. // Modifies the Google Test flags in the test body. TEST_F(GTestFlagSaverTest, ModifyGTestFlags) { VerifyAndModifyFlags(); } // Verifies that the Google Test flags in the body of the previous test were // restored to their original values. TEST_F(GTestFlagSaverTest, VerifyGTestFlags) { VerifyAndModifyFlags(); } // Sets an environment variable with the given name to the given // value. If the value argument is "", unsets the environment // variable. The caller must ensure that both arguments are not NULL. static void SetEnv(const char* name, const char* value) { #if GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. return; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // C++Builder's putenv only stores a pointer to its parameter; we have to // ensure that the string remains valid as long as it might be needed. // We use an std::map to do so. static std::map added_env; // Because putenv stores a pointer to the string buffer, we can't delete the // previous string (if present) until after it's replaced. std::string *prev_env = NULL; if (added_env.find(name) != added_env.end()) { prev_env = added_env[name]; } added_env[name] = new std::string( (Message() << name << "=" << value).GetString()); // The standard signature of putenv accepts a 'char*' argument. Other // implementations, like C++Builder's, accept a 'const char*'. // We cast away the 'const' since that would work for both variants. putenv(const_cast(added_env[name]->c_str())); delete prev_env; #elif GTEST_OS_WINDOWS // If we are on Windows proper. _putenv((Message() << name << "=" << value).GetString().c_str()); #else if (*value == '\0') { unsetenv(name); } else { setenv(name, value, 1); } #endif // GTEST_OS_WINDOWS_MOBILE } #if !GTEST_OS_WINDOWS_MOBILE // Environment variables are not supported on Windows CE. using testing::internal::Int32FromGTestEnv; // Tests Int32FromGTestEnv(). // Tests that Int32FromGTestEnv() returns the default value when the // environment variable is not set. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", ""); EXPECT_EQ(10, Int32FromGTestEnv("temp", 10)); } // Tests that Int32FromGTestEnv() returns the default value when the // environment variable overflows as an Int32. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows) { printf("(expecting 2 warnings)\n"); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321"); EXPECT_EQ(20, Int32FromGTestEnv("temp", 20)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321"); EXPECT_EQ(30, Int32FromGTestEnv("temp", 30)); } // Tests that Int32FromGTestEnv() returns the default value when the // environment variable does not represent a valid decimal integer. TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid) { printf("(expecting 2 warnings)\n"); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1"); EXPECT_EQ(40, Int32FromGTestEnv("temp", 40)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X"); EXPECT_EQ(50, Int32FromGTestEnv("temp", 50)); } // Tests that Int32FromGTestEnv() parses and returns the value of the // environment variable when it represents a valid decimal integer in // the range of an Int32. TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123"); EXPECT_EQ(123, Int32FromGTestEnv("temp", 0)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321"); EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests ParseInt32Flag(). // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag has wrong format TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag) { Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag overflows as an Int32. TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows) { printf("(expecting 2 warnings)\n"); Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() returns false and doesn't change the // output value when the flag does not represent a valid decimal // integer. TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid) { printf("(expecting 2 warnings)\n"); Int32 value = 123; EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value)); EXPECT_EQ(123, value); EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value)); EXPECT_EQ(123, value); } // Tests that ParseInt32Flag() parses the value of the flag and // returns true when the flag represents a valid decimal integer in // the range of an Int32. TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { Int32 value = 123; EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value)); EXPECT_EQ(456, value); EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789", "abc", &value)); EXPECT_EQ(-789, value); } // Tests that Int32FromEnvOrDie() parses the value of the var or // returns the correct default. // Environment variables are not supported on Windows CE. #if !GTEST_OS_WINDOWS_MOBILE TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123"); EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable is not an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx"); EXPECT_DEATH_IF_SUPPORTED( Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), ".*"); } // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable cannot be represnted by an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234"); EXPECT_DEATH_IF_SUPPORTED( Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), ".*"); } // Tests that ShouldRunTestOnShard() selects all tests // where there is 1 shard. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3)); EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4)); } class ShouldShardTest : public testing::Test { protected: virtual void SetUp() { index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX"; total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL"; } virtual void TearDown() { SetEnv(index_var_, ""); SetEnv(total_var_, ""); } const char* index_var_; const char* total_var_; }; // Tests that sharding is disabled if neither of the environment variables // are set. TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) { SetEnv(index_var_, ""); SetEnv(total_var_, ""); EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } // Tests that sharding is not enabled if total_shards == 1. TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { SetEnv(index_var_, "0"); SetEnv(total_var_, "1"); EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } // Tests that sharding is enabled if total_shards > 1 and // we are not in a death test subprocess. // Environment variables are not supported on Windows CE. #if !GTEST_OS_WINDOWS_MOBILE TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "22"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); SetEnv(index_var_, "8"); SetEnv(total_var_, "9"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); SetEnv(index_var_, "0"); SetEnv(total_var_, "9"); EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Tests that we exit in error if the sharding values are not valid. typedef ShouldShardTest ShouldShardDeathTest; TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "4"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, "4"); SetEnv(total_var_, "-2"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, "5"); SetEnv(total_var_, ""); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); SetEnv(index_var_, ""); SetEnv(total_var_, "5"); EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); } // Tests that ShouldRunTestOnShard is a partition when 5 // shards are used. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { // Choose an arbitrary number of tests and shards. const int num_tests = 17; const int num_shards = 5; // Check partitioning: each test should be on exactly 1 shard. for (int test_id = 0; test_id < num_tests; test_id++) { int prev_selected_shard_index = -1; for (int shard_index = 0; shard_index < num_shards; shard_index++) { if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) { if (prev_selected_shard_index < 0) { prev_selected_shard_index = shard_index; } else { ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and " << shard_index << " are both selected to run test " << test_id; } } } } // Check balance: This is not required by the sharding protocol, but is a // desirable property for performance. for (int shard_index = 0; shard_index < num_shards; shard_index++) { int num_tests_on_shard = 0; for (int test_id = 0; test_id < num_tests; test_id++) { num_tests_on_shard += ShouldRunTestOnShard(num_shards, shard_index, test_id); } EXPECT_GE(num_tests_on_shard, num_tests / num_shards); } } // For the same reason we are not explicitly testing everything in the // Test class, there are no separate tests for the following classes // (except for some trivial cases): // // TestCase, UnitTest, UnitTestResultPrinter. // // Similarly, there are no separate tests for the following macros: // // TEST, TEST_F, RUN_ALL_TESTS TEST(UnitTestTest, CanGetOriginalWorkingDir) { ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != NULL); EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), ""); } TEST(UnitTestTest, ReturnsPlausibleTimestamp) { EXPECT_LT(0, UnitTest::GetInstance()->start_timestamp()); EXPECT_LE(UnitTest::GetInstance()->start_timestamp(), GetTimeInMillis()); } // When a property using a reserved key is supplied to this function, it // tests that a non-fatal failure is added, a fatal failure is not added, // and that the property is not recorded. void ExpectNonFatalFailureRecordingPropertyWithReservedKey( const TestResult& test_result, const char* key) { EXPECT_NONFATAL_FAILURE(Test::RecordProperty(key, "1"), "Reserved key"); ASSERT_EQ(0, test_result.test_property_count()) << "Property for key '" << key << "' recorded unexpectedly."; } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( const char* key) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(test_info != NULL); ExpectNonFatalFailureRecordingPropertyWithReservedKey(*test_info->result(), key); } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( const char* key) { const TestCase* test_case = UnitTest::GetInstance()->current_test_case(); ASSERT_TRUE(test_case != NULL); ExpectNonFatalFailureRecordingPropertyWithReservedKey( test_case->ad_hoc_test_result(), key); } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( const char* key) { ExpectNonFatalFailureRecordingPropertyWithReservedKey( UnitTest::GetInstance()->ad_hoc_test_result(), key); } // Tests that property recording functions in UnitTest outside of tests // functions correcly. Creating a separate instance of UnitTest ensures it // is in a state similar to the UnitTest's singleton's between tests. class UnitTestRecordPropertyTest : public testing::internal::UnitTestRecordPropertyTestHelper { public: static void SetUpTestCase() { ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "disabled"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "errors"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "failures"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "tests"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "time"); Test::RecordProperty("test_case_key_1", "1"); const TestCase* test_case = UnitTest::GetInstance()->current_test_case(); ASSERT_TRUE(test_case != NULL); ASSERT_EQ(1, test_case->ad_hoc_test_result().test_property_count()); EXPECT_STREQ("test_case_key_1", test_case->ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", test_case->ad_hoc_test_result().GetTestProperty(0).value()); } }; // Tests TestResult has the expected property when added. TEST_F(UnitTestRecordPropertyTest, OnePropertyFoundWhenAdded) { UnitTestRecordProperty("key_1", "1"); ASSERT_EQ(1, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); } // Tests TestResult has multiple properties when added. TEST_F(UnitTestRecordPropertyTest, MultiplePropertiesFoundWhenAdded) { UnitTestRecordProperty("key_1", "1"); UnitTestRecordProperty("key_2", "2"); ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); EXPECT_STREQ("key_2", unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); EXPECT_STREQ("2", unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); } // Tests TestResult::RecordProperty() overrides values for duplicate keys. TEST_F(UnitTestRecordPropertyTest, OverridesValuesForDuplicateKeys) { UnitTestRecordProperty("key_1", "1"); UnitTestRecordProperty("key_2", "2"); UnitTestRecordProperty("key_1", "12"); UnitTestRecordProperty("key_2", "22"); ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("12", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); EXPECT_STREQ("key_2", unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); EXPECT_STREQ("22", unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); } TEST_F(UnitTestRecordPropertyTest, AddFailureInsideTestsWhenUsingTestCaseReservedKeys) { ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "value_param"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "type_param"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "status"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "time"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "classname"); } TEST_F(UnitTestRecordPropertyTest, AddRecordWithReservedKeysGeneratesCorrectPropertyList) { EXPECT_NONFATAL_FAILURE( Test::RecordProperty("name", "1"), "'classname', 'name', 'status', 'time', 'type_param', and 'value_param'" " are reserved"); } class UnitTestRecordPropertyTestEnvironment : public Environment { public: virtual void TearDown() { ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "tests"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "failures"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "disabled"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "errors"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "timestamp"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "time"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "random_seed"); } }; // This will test property recording outside of any test or test case. static Environment* record_property_env = AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment); // This group of tests is for predicate assertions (ASSERT_PRED*, etc) // of various arities. They do not attempt to be exhaustive. Rather, // view them as smoke tests that can be easily reviewed and verified. // A more complete set of tests for predicate assertions can be found // in gtest_pred_impl_unittest.cc. // First, some predicates and predicate-formatters needed by the tests. // Returns true iff the argument is an even number. bool IsEven(int n) { return (n % 2) == 0; } // A functor that returns true iff the argument is an even number. struct IsEvenFunctor { bool operator()(int n) { return IsEven(n); } }; // A predicate-formatter function that asserts the argument is an even // number. AssertionResult AssertIsEven(const char* expr, int n) { if (IsEven(n)) { return AssertionSuccess(); } Message msg; msg << expr << " evaluates to " << n << ", which is not even."; return AssertionFailure(msg); } // A predicate function that returns AssertionResult for use in // EXPECT/ASSERT_TRUE/FALSE. AssertionResult ResultIsEven(int n) { if (IsEven(n)) return AssertionSuccess() << n << " is even"; else return AssertionFailure() << n << " is odd"; } // A predicate function that returns AssertionResult but gives no // explanation why it succeeds. Needed for testing that // EXPECT/ASSERT_FALSE handles such functions correctly. AssertionResult ResultIsEvenNoExplanation(int n) { if (IsEven(n)) return AssertionSuccess(); else return AssertionFailure() << n << " is odd"; } // A predicate-formatter functor that asserts the argument is an even // number. struct AssertIsEvenFunctor { AssertionResult operator()(const char* expr, int n) { return AssertIsEven(expr, n); } }; // Returns true iff the sum of the arguments is an even number. bool SumIsEven2(int n1, int n2) { return IsEven(n1 + n2); } // A functor that returns true iff the sum of the arguments is an even // number. struct SumIsEven3Functor { bool operator()(int n1, int n2, int n3) { return IsEven(n1 + n2 + n3); } }; // A predicate-formatter function that asserts the sum of the // arguments is an even number. AssertionResult AssertSumIsEven4( const char* e1, const char* e2, const char* e3, const char* e4, int n1, int n2, int n3, int n4) { const int sum = n1 + n2 + n3 + n4; if (IsEven(sum)) { return AssertionSuccess(); } Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 << ") evaluates to " << sum << ", which is not even."; return AssertionFailure(msg); } // A predicate-formatter functor that asserts the sum of the arguments // is an even number. struct AssertSumIsEven5Functor { AssertionResult operator()( const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, int n1, int n2, int n3, int n4, int n5) { const int sum = n1 + n2 + n3 + n4 + n5; if (IsEven(sum)) { return AssertionSuccess(); } Message msg; msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5 << ") evaluates to " << sum << ", which is not even."; return AssertionFailure(msg); } }; // Tests unary predicate assertions. // Tests unary predicate assertions that don't use a custom formatter. TEST(Pred1Test, WithoutFormat) { // Success cases. EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!"; ASSERT_PRED1(IsEven, 4); // Failure cases. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED1(IsEven, 5) << "This failure is expected."; }, "This failure is expected."); EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5), "evaluates to false"); } // Tests unary predicate assertions that use a custom formatter. TEST(Pred1Test, WithFormat) { // Success cases. EXPECT_PRED_FORMAT1(AssertIsEven, 2); ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4) << "This failure is UNEXPECTED!"; // Failure cases. const int n = 5; EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n), "n evaluates to 5, which is not even."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected."; }, "This failure is expected."); } // Tests that unary predicate assertions evaluates their arguments // exactly once. TEST(Pred1Test, SingleEvaluationOnFailure) { // A success case. static int n = 0; EXPECT_PRED1(IsEven, n++); EXPECT_EQ(1, n) << "The argument is not evaluated exactly once."; // A failure case. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++) << "This failure is expected."; }, "This failure is expected."); EXPECT_EQ(2, n) << "The argument is not evaluated exactly once."; } // Tests predicate assertions whose arity is >= 2. // Tests predicate assertions that don't use a custom formatter. TEST(PredTest, WithoutFormat) { // Success cases. ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!"; EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8); // Failure cases. const int n1 = 1; const int n2 = 2; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected."; }, "This failure is expected."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4); }, "evaluates to false"); } // Tests predicate assertions that use a custom formatter. TEST(PredTest, WithFormat) { // Success cases. ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) << "This failure is UNEXPECTED!"; EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10); // Failure cases. const int n1 = 1; const int n2 = 2; const int n3 = 4; const int n4 = 6; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4); }, "evaluates to 13, which is not even."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8) << "This failure is expected."; }, "This failure is expected."); } // Tests that predicate assertions evaluates their arguments // exactly once. TEST(PredTest, SingleEvaluationOnFailure) { // A success case. int n1 = 0; int n2 = 0; EXPECT_PRED2(SumIsEven2, n1++, n2++); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; // Another success case. n1 = n2 = 0; int n3 = 0; int n4 = 0; int n5 = 0; ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), n1++, n2++, n3++, n4++, n5++) << "This failure is UNEXPECTED!"; EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once."; // A failure case. n1 = n2 = n3 = 0; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++) << "This failure is expected."; }, "This failure is expected."); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; // Another failure case. n1 = n2 = n3 = n4 = 0; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++); }, "evaluates to 1, which is not even."); EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; } // Some helper functions for testing using overloaded/template // functions with ASSERT_PREDn and EXPECT_PREDn. bool IsPositive(double x) { return x > 0; } template bool IsNegative(T x) { return x < 0; } template bool GreaterThan(T1 x1, T2 x2) { return x1 > x2; } // Tests that overloaded functions can be used in *_PRED* as long as // their types are explicitly specified. TEST(PredicateAssertionTest, AcceptsOverloadedFunction) { // C++Builder requires C-style casts rather than static_cast. EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT } // Tests that template functions can be used in *_PRED* as long as // their types are explicitly specified. TEST(PredicateAssertionTest, AcceptsTemplateFunction) { EXPECT_PRED1(IsNegative, -5); // Makes sure that we can handle templates with more than one // parameter. ASSERT_PRED2((GreaterThan), 5, 0); } // Some helper functions for testing using overloaded/template // functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn. AssertionResult IsPositiveFormat(const char* /* expr */, int n) { return n > 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } AssertionResult IsPositiveFormat(const char* /* expr */, double x) { return x > 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } template AssertionResult IsNegativeFormat(const char* /* expr */, T x) { return x < 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } template AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */, const T1& x1, const T2& x2) { return x1 == x2 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } // Tests that overloaded functions can be used in *_PRED_FORMAT* // without explicitly specifying their types. TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction) { EXPECT_PRED_FORMAT1(IsPositiveFormat, 5); ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0); } // Tests that template functions can be used in *_PRED_FORMAT* without // explicitly specifying their types. TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction) { EXPECT_PRED_FORMAT1(IsNegativeFormat, -5); ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3); } // Tests string assertions. // Tests ASSERT_STREQ with non-NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ) { const char * const p1 = "good"; ASSERT_STREQ(p1, p1); // Let p2 have the same content as p1, but be at a different address. const char p2[] = "good"; ASSERT_STREQ(p1, p2); EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"), "Expected: \"bad\""); } // Tests ASSERT_STREQ with NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ_Null) { ASSERT_STREQ(static_cast(NULL), NULL); EXPECT_FATAL_FAILURE(ASSERT_STREQ(NULL, "non-null"), "non-null"); } // Tests ASSERT_STREQ with NULL arguments. TEST(StringAssertionTest, ASSERT_STREQ_Null2) { EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", NULL), "non-null"); } // Tests ASSERT_STRNE. TEST(StringAssertionTest, ASSERT_STRNE) { ASSERT_STRNE("hi", "Hi"); ASSERT_STRNE("Hi", NULL); ASSERT_STRNE(NULL, "Hi"); ASSERT_STRNE("", NULL); ASSERT_STRNE(NULL, ""); ASSERT_STRNE("", "Hi"); ASSERT_STRNE("Hi", ""); EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"), "\"Hi\" vs \"Hi\""); } // Tests ASSERT_STRCASEEQ. TEST(StringAssertionTest, ASSERT_STRCASEEQ) { ASSERT_STRCASEEQ("hi", "Hi"); ASSERT_STRCASEEQ(static_cast(NULL), NULL); ASSERT_STRCASEEQ("", ""); EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"), "(ignoring case)"); } // Tests ASSERT_STRCASENE. TEST(StringAssertionTest, ASSERT_STRCASENE) { ASSERT_STRCASENE("hi1", "Hi2"); ASSERT_STRCASENE("Hi", NULL); ASSERT_STRCASENE(NULL, "Hi"); ASSERT_STRCASENE("", NULL); ASSERT_STRCASENE(NULL, ""); ASSERT_STRCASENE("", "Hi"); ASSERT_STRCASENE("Hi", ""); EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"), "(ignoring case)"); } // Tests *_STREQ on wide strings. TEST(StringAssertionTest, STREQ_Wide) { // NULL strings. ASSERT_STREQ(static_cast(NULL), NULL); // Empty strings. ASSERT_STREQ(L"", L""); // Non-null vs NULL. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", NULL), "non-null"); // Equal strings. EXPECT_STREQ(L"Hi", L"Hi"); // Unequal strings. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"), "Abc"); // Strings containing wide characters. EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"), "abc"); // The streaming variation. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_STREQ(L"abc\x8119", L"abc\x8121") << "Expected failure"; }, "Expected failure"); } // Tests *_STRNE on wide strings. TEST(StringAssertionTest, STRNE_Wide) { // NULL strings. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_STRNE(static_cast(NULL), NULL); }, ""); // Empty strings. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""), "L\"\""); // Non-null vs NULL. ASSERT_STRNE(L"non-null", NULL); // Equal strings. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"), "L\"Hi\""); // Unequal strings. EXPECT_STRNE(L"abc", L"Abc"); // Strings containing wide characters. EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"), "abc"); // The streaming variation. ASSERT_STRNE(L"abc\x8119", L"abc\x8120") << "This shouldn't happen"; } // Tests for ::testing::IsSubstring(). // Tests that IsSubstring() returns the correct result when the input // argument type is const char*. TEST(IsSubstringTest, ReturnsCorrectResultForCString) { EXPECT_FALSE(IsSubstring("", "", NULL, "a")); EXPECT_FALSE(IsSubstring("", "", "b", NULL)); EXPECT_FALSE(IsSubstring("", "", "needle", "haystack")); EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); EXPECT_TRUE(IsSubstring("", "", "needle", "two needles")); } // Tests that IsSubstring() returns the correct result when the input // argument type is const wchar_t*. TEST(IsSubstringTest, ReturnsCorrectResultForWideCString) { EXPECT_FALSE(IsSubstring("", "", kNull, L"a")); EXPECT_FALSE(IsSubstring("", "", L"b", kNull)); EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack")); EXPECT_TRUE(IsSubstring("", "", static_cast(NULL), NULL)); EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles")); } // Tests that IsSubstring() generates the correct message when the input // argument type is const char*. TEST(IsSubstringTest, GeneratesCorrectMessageForCString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: \"needle\"\n" "Expected: a substring of haystack_expr\n" "Which is: \"haystack\"", IsSubstring("needle_expr", "haystack_expr", "needle", "haystack").failure_message()); } // Tests that IsSubstring returns the correct result when the input // argument type is ::std::string. TEST(IsSubstringTest, ReturnsCorrectResultsForStdString) { EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob")); EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world"))); } #if GTEST_HAS_STD_WSTRING // Tests that IsSubstring returns the correct result when the input // argument type is ::std::wstring. TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring) { EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles")); EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack"))); } // Tests that IsSubstring() generates the correct message when the input // argument type is ::std::wstring. TEST(IsSubstringTest, GeneratesCorrectMessageForWstring) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: L\"needle\"\n" "Expected: a substring of haystack_expr\n" "Which is: L\"haystack\"", IsSubstring( "needle_expr", "haystack_expr", ::std::wstring(L"needle"), L"haystack").failure_message()); } #endif // GTEST_HAS_STD_WSTRING // Tests for ::testing::IsNotSubstring(). // Tests that IsNotSubstring() returns the correct result when the input // argument type is const char*. TEST(IsNotSubstringTest, ReturnsCorrectResultForCString) { EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack")); EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles")); } // Tests that IsNotSubstring() returns the correct result when the input // argument type is const wchar_t*. TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString) { EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack")); EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles")); } // Tests that IsNotSubstring() generates the correct message when the input // argument type is const wchar_t*. TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: L\"needle\"\n" "Expected: not a substring of haystack_expr\n" "Which is: L\"two needles\"", IsNotSubstring( "needle_expr", "haystack_expr", L"needle", L"two needles").failure_message()); } // Tests that IsNotSubstring returns the correct result when the input // argument type is ::std::string. TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString) { EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob")); EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world"))); } // Tests that IsNotSubstring() generates the correct message when the input // argument type is ::std::string. TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString) { EXPECT_STREQ("Value of: needle_expr\n" " Actual: \"needle\"\n" "Expected: not a substring of haystack_expr\n" "Which is: \"two needles\"", IsNotSubstring( "needle_expr", "haystack_expr", ::std::string("needle"), "two needles").failure_message()); } #if GTEST_HAS_STD_WSTRING // Tests that IsNotSubstring returns the correct result when the input // argument type is ::std::wstring. TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring) { EXPECT_FALSE( IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles")); EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack"))); } #endif // GTEST_HAS_STD_WSTRING // Tests floating-point assertions. template class FloatingPointTest : public Test { protected: // Pre-calculated numbers to be used by the tests. struct TestValues { RawType close_to_positive_zero; RawType close_to_negative_zero; RawType further_from_negative_zero; RawType close_to_one; RawType further_from_one; RawType infinity; RawType close_to_infinity; RawType further_from_infinity; RawType nan1; RawType nan2; }; typedef typename testing::internal::FloatingPoint Floating; typedef typename Floating::Bits Bits; virtual void SetUp() { const size_t max_ulps = Floating::kMaxUlps; // The bits that represent 0.0. const Bits zero_bits = Floating(0).bits(); // Makes some numbers close to 0.0. values_.close_to_positive_zero = Floating::ReinterpretBits( zero_bits + max_ulps/2); values_.close_to_negative_zero = -Floating::ReinterpretBits( zero_bits + max_ulps - max_ulps/2); values_.further_from_negative_zero = -Floating::ReinterpretBits( zero_bits + max_ulps + 1 - max_ulps/2); // The bits that represent 1.0. const Bits one_bits = Floating(1).bits(); // Makes some numbers close to 1.0. values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps); values_.further_from_one = Floating::ReinterpretBits( one_bits + max_ulps + 1); // +infinity. values_.infinity = Floating::Infinity(); // The bits that represent +infinity. const Bits infinity_bits = Floating(values_.infinity).bits(); // Makes some numbers close to infinity. values_.close_to_infinity = Floating::ReinterpretBits( infinity_bits - max_ulps); values_.further_from_infinity = Floating::ReinterpretBits( infinity_bits - max_ulps - 1); // Makes some NAN's. Sets the most significant bit of the fraction so that // our NaN's are quiet; trying to process a signaling NaN would raise an // exception if our environment enables floating point exceptions. values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 1); values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 200); } void TestSize() { EXPECT_EQ(sizeof(RawType), sizeof(Bits)); } static TestValues values_; }; template typename FloatingPointTest::TestValues FloatingPointTest::values_; // Instantiates FloatingPointTest for testing *_FLOAT_EQ. typedef FloatingPointTest FloatTest; // Tests that the size of Float::Bits matches the size of float. TEST_F(FloatTest, Size) { TestSize(); } // Tests comparing with +0 and -0. TEST_F(FloatTest, Zeros) { EXPECT_FLOAT_EQ(0.0, -0.0); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0), "1.0"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5), "1.5"); } // Tests comparing numbers close to 0. // // This ensures that *_FLOAT_EQ handles the sign correctly and no // overflow occurs when comparing numbers whose absolute value is very // small. TEST_F(FloatTest, AlmostZeros) { // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const FloatTest::TestValues& v = this->values_; EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero); EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero); EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_FLOAT_EQ(v.close_to_positive_zero, v.further_from_negative_zero); }, "v.further_from_negative_zero"); } // Tests comparing numbers close to each other. TEST_F(FloatTest, SmallDiff) { EXPECT_FLOAT_EQ(1.0, values_.close_to_one); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one), "values_.further_from_one"); } // Tests comparing numbers far apart. TEST_F(FloatTest, LargeDiff) { EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0), "3.0"); } // Tests comparing with infinity. // // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(FloatTest, Infinity) { EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity); EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity), "-values_.infinity"); // This is interesting as the representations of infinity and nan1 // are only 1 DLP apart. EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1), "values_.nan1"); #endif // !GTEST_OS_SYMBIAN } // Tests that comparing with NAN always returns false. TEST_F(FloatTest, NaN) { #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const FloatTest::TestValues& v = this->values_; EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1), "v.nan1"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity), "v.infinity"); #endif // !GTEST_OS_SYMBIAN } // Tests that *_FLOAT_EQ are reflexive. TEST_F(FloatTest, Reflexive) { EXPECT_FLOAT_EQ(0.0, 0.0); EXPECT_FLOAT_EQ(1.0, 1.0); ASSERT_FLOAT_EQ(values_.infinity, values_.infinity); } // Tests that *_FLOAT_EQ are commutative. TEST_F(FloatTest, Commutative) { // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one). EXPECT_FLOAT_EQ(values_.close_to_one, 1.0); // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one). EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0), "1.0"); } // Tests EXPECT_NEAR. TEST_F(FloatTest, EXPECT_NEAR) { EXPECT_NEAR(-1.0f, -1.1f, 0.2f); EXPECT_NEAR(2.0f, 3.0f, 1.0f); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT "The difference between 1.0f and 1.5f is 0.5, " "which exceeds 0.25f"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous line. } // Tests ASSERT_NEAR. TEST_F(FloatTest, ASSERT_NEAR) { ASSERT_NEAR(-1.0f, -1.1f, 0.2f); ASSERT_NEAR(2.0f, 3.0f, 1.0f); EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT "The difference between 1.0f and 1.5f is 0.5, " "which exceeds 0.25f"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous line. } // Tests the cases where FloatLE() should succeed. TEST_F(FloatTest, FloatLESucceeds) { EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2, ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2, // or when val1 is greater than, but almost equals to, val2. EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f); } // Tests the cases where FloatLE() should fail. TEST_F(FloatTest, FloatLEFails) { // When val1 is greater than val2 by a large margin, EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f), "(2.0f) <= (1.0f)"); // or by a small yet non-negligible margin, EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f); }, "(values_.further_from_one) <= (1.0f)"); #if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) // Nokia's STLport crashes if we try to output infinity or NaN. // C++Builder gives bad results for ordered comparisons involving NaNs // due to compiler bugs. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity); }, "(values_.nan1) <= (values_.infinity)"); EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1); }, "(-values_.infinity) <= (values_.nan1)"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1); }, "(values_.nan1) <= (values_.nan1)"); #endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) } // Instantiates FloatingPointTest for testing *_DOUBLE_EQ. typedef FloatingPointTest DoubleTest; // Tests that the size of Double::Bits matches the size of double. TEST_F(DoubleTest, Size) { TestSize(); } // Tests comparing with +0 and -0. TEST_F(DoubleTest, Zeros) { EXPECT_DOUBLE_EQ(0.0, -0.0); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0), "1.0"); EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0), "1.0"); } // Tests comparing numbers close to 0. // // This ensures that *_DOUBLE_EQ handles the sign correctly and no // overflow occurs when comparing numbers whose absolute value is very // small. TEST_F(DoubleTest, AlmostZeros) { // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const DoubleTest::TestValues& v = this->values_; EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero); EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero); EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_DOUBLE_EQ(v.close_to_positive_zero, v.further_from_negative_zero); }, "v.further_from_negative_zero"); } // Tests comparing numbers close to each other. TEST_F(DoubleTest, SmallDiff) { EXPECT_DOUBLE_EQ(1.0, values_.close_to_one); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one), "values_.further_from_one"); } // Tests comparing numbers far apart. TEST_F(DoubleTest, LargeDiff) { EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0), "3.0"); } // Tests comparing with infinity. // // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(DoubleTest, Infinity) { EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity); EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity), "-values_.infinity"); // This is interesting as the representations of infinity_ and nan1_ // are only 1 DLP apart. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1), "values_.nan1"); #endif // !GTEST_OS_SYMBIAN } // Tests that comparing with NAN always returns false. TEST_F(DoubleTest, NaN) { #if !GTEST_OS_SYMBIAN // In C++Builder, names within local classes (such as used by // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the // scoping class. Use a static local alias as a workaround. // We use the assignment syntax since some compilers, like Sun Studio, // don't allow initializing references using construction syntax // (parentheses). static const DoubleTest::TestValues& v = this->values_; // Nokia's STLport crashes if we try to output infinity or NaN. EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1"); EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity), "v.infinity"); #endif // !GTEST_OS_SYMBIAN } // Tests that *_DOUBLE_EQ are reflexive. TEST_F(DoubleTest, Reflexive) { EXPECT_DOUBLE_EQ(0.0, 0.0); EXPECT_DOUBLE_EQ(1.0, 1.0); #if !GTEST_OS_SYMBIAN // Nokia's STLport crashes if we try to output infinity or NaN. ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity); #endif // !GTEST_OS_SYMBIAN } // Tests that *_DOUBLE_EQ are commutative. TEST_F(DoubleTest, Commutative) { // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one). EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0); // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one). EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0), "1.0"); } // Tests EXPECT_NEAR. TEST_F(DoubleTest, EXPECT_NEAR) { EXPECT_NEAR(-1.0, -1.1, 0.2); EXPECT_NEAR(2.0, 3.0, 1.0); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests ASSERT_NEAR. TEST_F(DoubleTest, ASSERT_NEAR) { ASSERT_NEAR(-1.0, -1.1, 0.2); ASSERT_NEAR(2.0, 3.0, 1.0); EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests the cases where DoubleLE() should succeed. TEST_F(DoubleTest, DoubleLESucceeds) { EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2, ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2, // or when val1 is greater than, but almost equals to, val2. EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0); } // Tests the cases where DoubleLE() should fail. TEST_F(DoubleTest, DoubleLEFails) { // When val1 is greater than val2 by a large margin, EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0), "(2.0) <= (1.0)"); // or by a small yet non-negligible margin, EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0); }, "(values_.further_from_one) <= (1.0)"); #if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) // Nokia's STLport crashes if we try to output infinity or NaN. // C++Builder gives bad results for ordered comparisons involving NaNs // due to compiler bugs. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity); }, "(values_.nan1) <= (values_.infinity)"); EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1); }, " (-values_.infinity) <= (values_.nan1)"); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1); }, "(values_.nan1) <= (values_.nan1)"); #endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__) } // Verifies that a test or test case whose name starts with DISABLED_ is // not run. // A test whose name starts with DISABLED_. // Should not run. TEST(DisabledTest, DISABLED_TestShouldNotRun) { FAIL() << "Unexpected failure: Disabled test should not be run."; } // A test whose name does not start with DISABLED_. // Should run. TEST(DisabledTest, NotDISABLED_TestShouldRun) { EXPECT_EQ(1, 1); } // A test case whose name starts with DISABLED_. // Should not run. TEST(DISABLED_TestCase, TestShouldNotRun) { FAIL() << "Unexpected failure: Test in disabled test case should not be run."; } // A test case and test whose names start with DISABLED_. // Should not run. TEST(DISABLED_TestCase, DISABLED_TestShouldNotRun) { FAIL() << "Unexpected failure: Test in disabled test case should not be run."; } // Check that when all tests in a test case are disabled, SetupTestCase() and // TearDownTestCase() are not called. class DisabledTestsTest : public Test { protected: static void SetUpTestCase() { FAIL() << "Unexpected failure: All tests disabled in test case. " "SetupTestCase() should not be called."; } static void TearDownTestCase() { FAIL() << "Unexpected failure: All tests disabled in test case. " "TearDownTestCase() should not be called."; } }; TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1) { FAIL() << "Unexpected failure: Disabled test should not be run."; } TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) { FAIL() << "Unexpected failure: Disabled test should not be run."; } // Tests that disabled typed tests aren't run. #if GTEST_HAS_TYPED_TEST template class TypedTest : public Test { }; typedef testing::Types NumericTypes; TYPED_TEST_CASE(TypedTest, NumericTypes); TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { FAIL() << "Unexpected failure: Disabled typed test should not run."; } template class DISABLED_TypedTest : public Test { }; TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes); TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) { FAIL() << "Unexpected failure: Disabled typed test should not run."; } #endif // GTEST_HAS_TYPED_TEST // Tests that disabled type-parameterized tests aren't run. #if GTEST_HAS_TYPED_TEST_P template class TypedTestP : public Test { }; TYPED_TEST_CASE_P(TypedTestP); TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) { FAIL() << "Unexpected failure: " << "Disabled type-parameterized test should not run."; } REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun); INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes); template class DISABLED_TypedTestP : public Test { }; TYPED_TEST_CASE_P(DISABLED_TypedTestP); TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) { FAIL() << "Unexpected failure: " << "Disabled type-parameterized test should not run."; } REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun); INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes); #endif // GTEST_HAS_TYPED_TEST_P // Tests that assertion macros evaluate their arguments exactly once. class SingleEvaluationTest : public Test { public: // Must be public and not protected due to a bug in g++ 3.4.2. // This helper function is needed by the FailedASSERT_STREQ test // below. It's public to work around C++Builder's bug with scoping local // classes. static void CompareAndIncrementCharPtrs() { ASSERT_STREQ(p1_++, p2_++); } // This helper function is needed by the FailedASSERT_NE test below. It's // public to work around C++Builder's bug with scoping local classes. static void CompareAndIncrementInts() { ASSERT_NE(a_++, b_++); } protected: SingleEvaluationTest() { p1_ = s1_; p2_ = s2_; a_ = 0; b_ = 0; } static const char* const s1_; static const char* const s2_; static const char* p1_; static const char* p2_; static int a_; static int b_; }; const char* const SingleEvaluationTest::s1_ = "01234"; const char* const SingleEvaluationTest::s2_ = "abcde"; const char* SingleEvaluationTest::p1_; const char* SingleEvaluationTest::p2_; int SingleEvaluationTest::a_; int SingleEvaluationTest::b_; // Tests that when ASSERT_STREQ fails, it evaluates its arguments // exactly once. TEST_F(SingleEvaluationTest, FailedASSERT_STREQ) { EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(), "p2_++"); EXPECT_EQ(s1_ + 1, p1_); EXPECT_EQ(s2_ + 1, p2_); } // Tests that string assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, ASSERT_STR) { // successful EXPECT_STRNE EXPECT_STRNE(p1_++, p2_++); EXPECT_EQ(s1_ + 1, p1_); EXPECT_EQ(s2_ + 1, p2_); // failed EXPECT_STRCASEEQ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++), "ignoring case"); EXPECT_EQ(s1_ + 2, p1_); EXPECT_EQ(s2_ + 2, p2_); } // Tests that when ASSERT_NE fails, it evaluates its arguments exactly // once. TEST_F(SingleEvaluationTest, FailedASSERT_NE) { EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(), "(a_++) != (b_++)"); EXPECT_EQ(1, a_); EXPECT_EQ(1, b_); } // Tests that assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, OtherCases) { // successful EXPECT_TRUE EXPECT_TRUE(0 == a_++); // NOLINT EXPECT_EQ(1, a_); // failed EXPECT_TRUE EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++"); EXPECT_EQ(2, a_); // successful EXPECT_GT EXPECT_GT(a_++, b_++); EXPECT_EQ(3, a_); EXPECT_EQ(1, b_); // failed EXPECT_LT EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)"); EXPECT_EQ(4, a_); EXPECT_EQ(2, b_); // successful ASSERT_TRUE ASSERT_TRUE(0 < a_++); // NOLINT EXPECT_EQ(5, a_); // successful ASSERT_GT ASSERT_GT(a_++, b_++); EXPECT_EQ(6, a_); EXPECT_EQ(3, b_); } #if GTEST_HAS_EXCEPTIONS void ThrowAnInteger() { throw 1; } // Tests that assertion arguments are evaluated exactly once. TEST_F(SingleEvaluationTest, ExceptionTests) { // successful EXPECT_THROW EXPECT_THROW({ // NOLINT a_++; ThrowAnInteger(); }, int); EXPECT_EQ(1, a_); // failed EXPECT_THROW, throws different EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT a_++; ThrowAnInteger(); }, bool), "throws a different type"); EXPECT_EQ(2, a_); // failed EXPECT_THROW, throws nothing EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); EXPECT_EQ(3, a_); // successful EXPECT_NO_THROW EXPECT_NO_THROW(a_++); EXPECT_EQ(4, a_); // failed EXPECT_NO_THROW EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT a_++; ThrowAnInteger(); }), "it throws"); EXPECT_EQ(5, a_); // successful EXPECT_ANY_THROW EXPECT_ANY_THROW({ // NOLINT a_++; ThrowAnInteger(); }); EXPECT_EQ(6, a_); // failed EXPECT_ANY_THROW EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); EXPECT_EQ(7, a_); } #endif // GTEST_HAS_EXCEPTIONS // Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE. class NoFatalFailureTest : public Test { protected: void Succeeds() {} void FailsNonFatal() { ADD_FAILURE() << "some non-fatal failure"; } void Fails() { FAIL() << "some fatal failure"; } void DoAssertNoFatalFailureOnFails() { ASSERT_NO_FATAL_FAILURE(Fails()); ADD_FAILURE() << "shold not reach here."; } void DoExpectNoFatalFailureOnFails() { EXPECT_NO_FATAL_FAILURE(Fails()); ADD_FAILURE() << "other failure"; } }; TEST_F(NoFatalFailureTest, NoFailure) { EXPECT_NO_FATAL_FAILURE(Succeeds()); ASSERT_NO_FATAL_FAILURE(Succeeds()); } TEST_F(NoFatalFailureTest, NonFatalIsNoFailure) { EXPECT_NONFATAL_FAILURE( EXPECT_NO_FATAL_FAILURE(FailsNonFatal()), "some non-fatal failure"); EXPECT_NONFATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(FailsNonFatal()), "some non-fatal failure"); } TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); DoAssertNoFatalFailureOnFails(); } ASSERT_EQ(2, gtest_failures.size()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", gtest_failures.GetTestPartResult(1).message()); } TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); DoExpectNoFatalFailureOnFails(); } ASSERT_EQ(3, gtest_failures.size()); EXPECT_EQ(TestPartResult::kFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(2).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", gtest_failures.GetTestPartResult(1).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure", gtest_failures.GetTestPartResult(2).message()); } TEST_F(NoFatalFailureTest, MessageIsStreamable) { TestPartResultArray gtest_failures; { ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message"; } ASSERT_EQ(2, gtest_failures.size()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(0).type()); EXPECT_EQ(TestPartResult::kNonFatalFailure, gtest_failures.GetTestPartResult(1).type()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo", gtest_failures.GetTestPartResult(0).message()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message", gtest_failures.GetTestPartResult(1).message()); } // Tests non-string assertions. // Tests EqFailure(), used for implementing *EQ* assertions. TEST(AssertionTest, EqFailure) { const std::string foo_val("5"), bar_val("6"); const std::string msg1( EqFailure("foo", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: 6\n" "Expected: foo\n" "Which is: 5", msg1.c_str()); const std::string msg2( EqFailure("foo", "6", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: 6\n" "Expected: foo\n" "Which is: 5", msg2.c_str()); const std::string msg3( EqFailure("5", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: 6\n" "Expected: 5", msg3.c_str()); const std::string msg4( EqFailure("5", "6", foo_val, bar_val, false).failure_message()); EXPECT_STREQ( "Value of: 6\n" "Expected: 5", msg4.c_str()); const std::string msg5( EqFailure("foo", "bar", std::string("\"x\""), std::string("\"y\""), true).failure_message()); EXPECT_STREQ( "Value of: bar\n" " Actual: \"y\"\n" "Expected: foo (ignoring case)\n" "Which is: \"x\"", msg5.c_str()); } // Tests AppendUserMessage(), used for implementing the *EQ* macros. TEST(AssertionTest, AppendUserMessage) { const std::string foo("foo"); Message msg; EXPECT_STREQ("foo", AppendUserMessage(foo, msg).c_str()); msg << "bar"; EXPECT_STREQ("foo\nbar", AppendUserMessage(foo, msg).c_str()); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" # pragma option push -w-ccc -w-rch #endif // Tests ASSERT_TRUE. TEST(AssertionTest, ASSERT_TRUE) { ASSERT_TRUE(2 > 1); // NOLINT EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1), "2 < 1"); } // Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult. TEST(AssertionTest, AssertTrueWithAssertionResult) { ASSERT_TRUE(ResultIsEven(2)); #ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)), "Value of: ResultIsEven(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); #endif ASSERT_TRUE(ResultIsEvenNoExplanation(2)); EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)), "Value of: ResultIsEvenNoExplanation(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); } // Tests ASSERT_FALSE. TEST(AssertionTest, ASSERT_FALSE) { ASSERT_FALSE(2 < 1); // NOLINT EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1), "Value of: 2 > 1\n" " Actual: true\n" "Expected: false"); } // Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult. TEST(AssertionTest, AssertFalseWithAssertionResult) { ASSERT_FALSE(ResultIsEven(3)); #ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)), "Value of: ResultIsEven(2)\n" " Actual: true (2 is even)\n" "Expected: false"); #endif ASSERT_FALSE(ResultIsEvenNoExplanation(3)); EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)), "Value of: ResultIsEvenNoExplanation(2)\n" " Actual: true\n" "Expected: false"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them # pragma option pop #endif // Tests using ASSERT_EQ on double values. The purpose is to make // sure that the specialization we did for integer and anonymous enums // isn't used for double arguments. TEST(ExpectTest, ASSERT_EQ_Double) { // A success. ASSERT_EQ(5.6, 5.6); // A failure. EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2), "5.1"); } // Tests ASSERT_EQ. TEST(AssertionTest, ASSERT_EQ) { ASSERT_EQ(5, 2 + 3); EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3), "Value of: 2*3\n" " Actual: 6\n" "Expected: 5"); } // Tests ASSERT_EQ(NULL, pointer). #if GTEST_CAN_COMPARE_NULL TEST(AssertionTest, ASSERT_EQ_NULL) { // A success. const char* p = NULL; // Some older GCC versions may issue a spurious waring in this or the next // assertion statement. This warning should not be suppressed with // static_cast since the test verifies the ability to use bare NULL as the // expected parameter to the macro. ASSERT_EQ(NULL, p); // A failure. static int n = 0; EXPECT_FATAL_FAILURE(ASSERT_EQ(NULL, &n), "Value of: &n\n"); } #endif // GTEST_CAN_COMPARE_NULL // Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be // treated as a null pointer by the compiler, we need to make sure // that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as // ASSERT_EQ(static_cast(NULL), non_pointer). TEST(ExpectTest, ASSERT_EQ_0) { int n = 0; // A success. ASSERT_EQ(0, n); // A failure. EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6), "Expected: 0"); } // Tests ASSERT_NE. TEST(AssertionTest, ASSERT_NE) { ASSERT_NE(6, 7); EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'), "Expected: ('a') != ('a'), " "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); } // Tests ASSERT_LE. TEST(AssertionTest, ASSERT_LE) { ASSERT_LE(2, 3); ASSERT_LE(2, 2); EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0), "Expected: (2) <= (0), actual: 2 vs 0"); } // Tests ASSERT_LT. TEST(AssertionTest, ASSERT_LT) { ASSERT_LT(2, 3); EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2), "Expected: (2) < (2), actual: 2 vs 2"); } // Tests ASSERT_GE. TEST(AssertionTest, ASSERT_GE) { ASSERT_GE(2, 1); ASSERT_GE(2, 2); EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3), "Expected: (2) >= (3), actual: 2 vs 3"); } // Tests ASSERT_GT. TEST(AssertionTest, ASSERT_GT) { ASSERT_GT(2, 1); EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2), "Expected: (2) > (2), actual: 2 vs 2"); } #if GTEST_HAS_EXCEPTIONS void ThrowNothing() {} // Tests ASSERT_THROW. TEST(AssertionTest, ASSERT_THROW) { ASSERT_THROW(ThrowAnInteger(), int); # ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE( ASSERT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of type bool.\n" " Actual: it throws a different type."); # endif EXPECT_FATAL_FAILURE( ASSERT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" " Actual: it throws nothing."); } // Tests ASSERT_NO_THROW. TEST(AssertionTest, ASSERT_NO_THROW) { ASSERT_NO_THROW(ThrowNothing()); EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()), "Expected: ThrowAnInteger() doesn't throw an exception." "\n Actual: it throws."); } // Tests ASSERT_ANY_THROW. TEST(AssertionTest, ASSERT_ANY_THROW) { ASSERT_ANY_THROW(ThrowAnInteger()); EXPECT_FATAL_FAILURE( ASSERT_ANY_THROW(ThrowNothing()), "Expected: ThrowNothing() throws an exception.\n" " Actual: it doesn't."); } #endif // GTEST_HAS_EXCEPTIONS // Makes sure we deal with the precedence of <<. This test should // compile. TEST(AssertionTest, AssertPrecedence) { ASSERT_EQ(1 < 2, true); bool false_value = false; ASSERT_EQ(true && false_value, false); } // A subroutine used by the following test. void TestEq1(int x) { ASSERT_EQ(1, x); } // Tests calling a test subroutine that's not part of a fixture. TEST(AssertionTest, NonFixtureSubroutine) { EXPECT_FATAL_FAILURE(TestEq1(2), "Value of: x"); } // An uncopyable class. class Uncopyable { public: explicit Uncopyable(int a_value) : value_(a_value) {} int value() const { return value_; } bool operator==(const Uncopyable& rhs) const { return value() == rhs.value(); } private: // This constructor deliberately has no implementation, as we don't // want this class to be copyable. Uncopyable(const Uncopyable&); // NOLINT int value_; }; ::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value) { return os << value.value(); } bool IsPositiveUncopyable(const Uncopyable& x) { return x.value() > 0; } // A subroutine used by the following test. void TestAssertNonPositive() { Uncopyable y(-1); ASSERT_PRED1(IsPositiveUncopyable, y); } // A subroutine used by the following test. void TestAssertEqualsUncopyable() { Uncopyable x(5); Uncopyable y(-1); ASSERT_EQ(x, y); } // Tests that uncopyable objects can be used in assertions. TEST(AssertionTest, AssertWorksWithUncopyableObject) { Uncopyable x(5); ASSERT_PRED1(IsPositiveUncopyable, x); ASSERT_EQ(x, x); EXPECT_FATAL_FAILURE(TestAssertNonPositive(), "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(), "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); } // Tests that uncopyable objects can be used in expects. TEST(AssertionTest, ExpectWorksWithUncopyableObject) { Uncopyable x(5); EXPECT_PRED1(IsPositiveUncopyable, x); Uncopyable y(-1); EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y), "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); EXPECT_EQ(x, x); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5"); } enum NamedEnum { kE1 = 0, kE2 = 1 }; TEST(AssertionTest, NamedEnum) { EXPECT_EQ(kE1, kE1); EXPECT_LT(kE1, kE2); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Actual: 1"); } // The version of gcc used in XCode 2.2 has a bug and doesn't allow // anonymous enums in assertions. Therefore the following test is not // done on Mac. // Sun Studio and HP aCC also reject this code. #if !GTEST_OS_MAC && !defined(__SUNPRO_CC) && !defined(__HP_aCC) // Tests using assertions with anonymous enums. enum { kCaseA = -1, # if GTEST_OS_LINUX // We want to test the case where the size of the anonymous enum is // larger than sizeof(int), to make sure our implementation of the // assertions doesn't truncate the enums. However, MSVC // (incorrectly) doesn't allow an enum value to exceed the range of // an int, so this has to be conditionally compiled. // // On Linux, kCaseB and kCaseA have the same value when truncated to // int size. We want to test whether this will confuse the // assertions. kCaseB = testing::internal::kMaxBiggestInt, # else kCaseB = INT_MAX, # endif // GTEST_OS_LINUX kCaseC = 42 }; TEST(AssertionTest, AnonymousEnum) { # if GTEST_OS_LINUX EXPECT_EQ(static_cast(kCaseA), static_cast(kCaseB)); # endif // GTEST_OS_LINUX EXPECT_EQ(kCaseA, kCaseA); EXPECT_NE(kCaseA, kCaseB); EXPECT_LT(kCaseA, kCaseB); EXPECT_LE(kCaseA, kCaseB); EXPECT_GT(kCaseB, kCaseA); EXPECT_GE(kCaseA, kCaseA); EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB), "(kCaseA) >= (kCaseB)"); EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC), "-1 vs 42"); ASSERT_EQ(kCaseA, kCaseA); ASSERT_NE(kCaseA, kCaseB); ASSERT_LT(kCaseA, kCaseB); ASSERT_LE(kCaseA, kCaseB); ASSERT_GT(kCaseB, kCaseA); ASSERT_GE(kCaseA, kCaseA); # ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB), "Value of: kCaseB"); EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), "Actual: 42"); # endif EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), "Which is: -1"); } #endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC) #if GTEST_OS_WINDOWS static HRESULT UnexpectedHRESULTFailure() { return E_UNEXPECTED; } static HRESULT OkHRESULTSuccess() { return S_OK; } static HRESULT FalseHRESULTSuccess() { return S_FALSE; } // HRESULT assertion tests test both zero and non-zero // success codes as well as failure message for each. // // Windows CE doesn't support message texts. TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) { EXPECT_HRESULT_SUCCEEDED(S_OK); EXPECT_HRESULT_SUCCEEDED(S_FALSE); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" " Actual: 0x8000FFFF"); } TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) { ASSERT_HRESULT_SUCCEEDED(S_OK); ASSERT_HRESULT_SUCCEEDED(S_FALSE); EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" " Actual: 0x8000FFFF"); } TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) { EXPECT_HRESULT_FAILED(E_UNEXPECTED); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()), "Expected: (OkHRESULTSuccess()) fails.\n" " Actual: 0x0"); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x1"); } TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) { ASSERT_HRESULT_FAILED(E_UNEXPECTED); # ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()), "Expected: (OkHRESULTSuccess()) fails.\n" " Actual: 0x0"); # endif EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x1"); } // Tests that streaming to the HRESULT macros works. TEST(HRESULTAssertionTest, Streaming) { EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; EXPECT_NONFATAL_FAILURE( EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", "expected failure"); # ifndef __BORLANDC__ // ICE's in C++Builder 2007 and 2009. EXPECT_FATAL_FAILURE( ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", "expected failure"); # endif EXPECT_NONFATAL_FAILURE( EXPECT_HRESULT_FAILED(S_OK) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE( ASSERT_HRESULT_FAILED(S_OK) << "expected failure", "expected failure"); } #endif // GTEST_OS_WINDOWS #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" # pragma option push -w-ccc -w-rch #endif // Tests that the assertion macros behave like single statements. TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) ASSERT_TRUE(false) << "This should never be executed; " "It's a compilation test only."; if (AlwaysTrue()) EXPECT_FALSE(false); else ; // NOLINT if (AlwaysFalse()) ASSERT_LT(1, 3); if (AlwaysFalse()) ; // NOLINT else EXPECT_GT(3, 2) << ""; } #if GTEST_HAS_EXCEPTIONS // Tests that the compiler will not complain about unreachable code in the // EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros. TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { int n = 0; EXPECT_THROW(throw 1, int); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), ""); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), ""); EXPECT_NO_THROW(n++); EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), ""); EXPECT_ANY_THROW(throw 1); EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); } TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_THROW(ThrowNothing(), bool); if (AlwaysTrue()) EXPECT_THROW(ThrowAnInteger(), int); else ; // NOLINT if (AlwaysFalse()) EXPECT_NO_THROW(ThrowAnInteger()); if (AlwaysTrue()) EXPECT_NO_THROW(ThrowNothing()); else ; // NOLINT if (AlwaysFalse()) EXPECT_ANY_THROW(ThrowNothing()); if (AlwaysTrue()) EXPECT_ANY_THROW(ThrowAnInteger()); else ; // NOLINT } #endif // GTEST_HAS_EXCEPTIONS TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { if (AlwaysFalse()) EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " << "It's a compilation test only."; else ; // NOLINT if (AlwaysFalse()) ASSERT_NO_FATAL_FAILURE(FAIL()) << ""; else ; // NOLINT if (AlwaysTrue()) EXPECT_NO_FATAL_FAILURE(SUCCEED()); else ; // NOLINT if (AlwaysFalse()) ; // NOLINT else ASSERT_NO_FATAL_FAILURE(SUCCEED()); } // Tests that the assertion macros work well with switch statements. TEST(AssertionSyntaxTest, WorksWithSwitch) { switch (0) { case 1: break; default: ASSERT_TRUE(true); } switch (0) case 0: EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case"; // Binary assertions are implemented using a different code path // than the Boolean assertions. Hence we test them separately. switch (0) { case 1: default: ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler"; } switch (0) case 0: EXPECT_NE(1, 2); } #if GTEST_HAS_EXCEPTIONS void ThrowAString() { throw "std::string"; } // Test that the exception assertion macros compile and work with const // type qualifier. TEST(AssertionSyntaxTest, WorksWithConst) { ASSERT_THROW(ThrowAString(), const char*); EXPECT_THROW(ThrowAString(), const char*); } #endif // GTEST_HAS_EXCEPTIONS } // namespace namespace testing { // Tests that Google Test tracks SUCCEED*. TEST(SuccessfulAssertionTest, SUCCEED) { SUCCEED(); SUCCEED() << "OK"; EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful EXPECT_*. TEST(SuccessfulAssertionTest, EXPECT) { EXPECT_TRUE(true); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful EXPECT_STR*. TEST(SuccessfulAssertionTest, EXPECT_STR) { EXPECT_STREQ("", ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful ASSERT_*. TEST(SuccessfulAssertionTest, ASSERT) { ASSERT_TRUE(true); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } // Tests that Google Test doesn't track successful ASSERT_STR*. TEST(SuccessfulAssertionTest, ASSERT_STR) { ASSERT_STREQ("", ""); EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); } } // namespace testing namespace { // Tests the message streaming variation of assertions. TEST(AssertionWithMessageTest, EXPECT) { EXPECT_EQ(1, 1) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_NE(1, 1) << "Expected failure #1.", "Expected failure #1"); EXPECT_LE(1, 2) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_LT(1, 0) << "Expected failure #2.", "Expected failure #2."); EXPECT_GE(1, 0) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_GT(1, 2) << "Expected failure #3.", "Expected failure #3."); EXPECT_STREQ("1", "1") << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("1", "1") << "Expected failure #4.", "Expected failure #4."); EXPECT_STRCASEEQ("a", "A") << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("a", "A") << "Expected failure #5.", "Expected failure #5."); EXPECT_FLOAT_EQ(1, 1) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1, 1.2) << "Expected failure #6.", "Expected failure #6."); EXPECT_NEAR(1, 1.1, 0.2) << "This should succeed."; } TEST(AssertionWithMessageTest, ASSERT) { ASSERT_EQ(1, 1) << "This should succeed."; ASSERT_NE(1, 2) << "This should succeed."; ASSERT_LE(1, 2) << "This should succeed."; ASSERT_LT(1, 2) << "This should succeed."; ASSERT_GE(1, 0) << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_GT(1, 2) << "Expected failure.", "Expected failure."); } TEST(AssertionWithMessageTest, ASSERT_STR) { ASSERT_STREQ("1", "1") << "This should succeed."; ASSERT_STRNE("1", "2") << "This should succeed."; ASSERT_STRCASEEQ("a", "A") << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("a", "A") << "Expected failure.", "Expected failure."); } TEST(AssertionWithMessageTest, ASSERT_FLOATING) { ASSERT_FLOAT_EQ(1, 1) << "This should succeed."; ASSERT_DOUBLE_EQ(1, 1) << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_NEAR(1,1.2, 0.1) << "Expect failure.", // NOLINT "Expect failure."); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests using ASSERT_FALSE with a streamed message. TEST(AssertionWithMessageTest, ASSERT_FALSE) { ASSERT_FALSE(false) << "This shouldn't fail."; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_FALSE(true) << "Expected failure: " << 2 << " > " << 1 << " evaluates to " << true; }, "Expected failure"); } // Tests using FAIL with a streamed message. TEST(AssertionWithMessageTest, FAIL) { EXPECT_FATAL_FAILURE(FAIL() << 0, "0"); } // Tests using SUCCEED with a streamed message. TEST(AssertionWithMessageTest, SUCCEED) { SUCCEED() << "Success == " << 1; } // Tests using ASSERT_TRUE with a streamed message. TEST(AssertionWithMessageTest, ASSERT_TRUE) { ASSERT_TRUE(true) << "This should succeed."; ASSERT_TRUE(true) << true; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_TRUE(false) << static_cast(NULL) << static_cast(NULL); }, "(null)(null)"); } #if GTEST_OS_WINDOWS // Tests using wide strings in assertion messages. TEST(AssertionWithMessageTest, WideStringMessage) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_TRUE(false) << L"This failure is expected.\x8119"; }, "This failure is expected."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(1, 2) << "This failure is " << L"expected too.\x8120"; }, "This failure is expected too."); } #endif // GTEST_OS_WINDOWS // Tests EXPECT_TRUE. TEST(ExpectTest, EXPECT_TRUE) { EXPECT_TRUE(true) << "Intentional success"; EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #1.", "Intentional failure #1."); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #2.", "Intentional failure #2."); EXPECT_TRUE(2 > 1); // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1), "Value of: 2 < 1\n" " Actual: false\n" "Expected: true"); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3), "2 > 3"); } // Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult. TEST(ExpectTest, ExpectTrueWithAssertionResult) { EXPECT_TRUE(ResultIsEven(2)); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)), "Value of: ResultIsEven(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); EXPECT_TRUE(ResultIsEvenNoExplanation(2)); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)), "Value of: ResultIsEvenNoExplanation(3)\n" " Actual: false (3 is odd)\n" "Expected: true"); } // Tests EXPECT_FALSE with a streamed message. TEST(ExpectTest, EXPECT_FALSE) { EXPECT_FALSE(2 < 1); // NOLINT EXPECT_FALSE(false) << "Intentional success"; EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #1.", "Intentional failure #1."); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #2.", "Intentional failure #2."); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1), "Value of: 2 > 1\n" " Actual: true\n" "Expected: false"); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3), "2 < 3"); } // Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult. TEST(ExpectTest, ExpectFalseWithAssertionResult) { EXPECT_FALSE(ResultIsEven(3)); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)), "Value of: ResultIsEven(2)\n" " Actual: true (2 is even)\n" "Expected: false"); EXPECT_FALSE(ResultIsEvenNoExplanation(3)); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)), "Value of: ResultIsEvenNoExplanation(2)\n" " Actual: true\n" "Expected: false"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them # pragma option pop #endif // Tests EXPECT_EQ. TEST(ExpectTest, EXPECT_EQ) { EXPECT_EQ(5, 2 + 3); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3), "Value of: 2*3\n" " Actual: 6\n" "Expected: 5"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3), "2 - 3"); } // Tests using EXPECT_EQ on double values. The purpose is to make // sure that the specialization we did for integer and anonymous enums // isn't used for double arguments. TEST(ExpectTest, EXPECT_EQ_Double) { // A success. EXPECT_EQ(5.6, 5.6); // A failure. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2), "5.1"); } #if GTEST_CAN_COMPARE_NULL // Tests EXPECT_EQ(NULL, pointer). TEST(ExpectTest, EXPECT_EQ_NULL) { // A success. const char* p = NULL; // Some older GCC versions may issue a spurious warning in this or the next // assertion statement. This warning should not be suppressed with // static_cast since the test verifies the ability to use bare NULL as the // expected parameter to the macro. EXPECT_EQ(NULL, p); // A failure. int n = 0; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(NULL, &n), "Value of: &n\n"); } #endif // GTEST_CAN_COMPARE_NULL // Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be // treated as a null pointer by the compiler, we need to make sure // that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as // EXPECT_EQ(static_cast(NULL), non_pointer). TEST(ExpectTest, EXPECT_EQ_0) { int n = 0; // A success. EXPECT_EQ(0, n); // A failure. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6), "Expected: 0"); } // Tests EXPECT_NE. TEST(ExpectTest, EXPECT_NE) { EXPECT_NE(6, 7); EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'), "Expected: ('a') != ('a'), " "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2), "2"); char* const p0 = NULL; EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0), "p0"); // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT char* const p1 = reinterpret_cast(pv1); EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1), "p1"); } // Tests EXPECT_LE. TEST(ExpectTest, EXPECT_LE) { EXPECT_LE(2, 3); EXPECT_LE(2, 2); EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0), "Expected: (2) <= (0), actual: 2 vs 0"); EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9), "(1.1) <= (0.9)"); } // Tests EXPECT_LT. TEST(ExpectTest, EXPECT_LT) { EXPECT_LT(2, 3); EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2), "Expected: (2) < (2), actual: 2 vs 2"); EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1), "(2) < (1)"); } // Tests EXPECT_GE. TEST(ExpectTest, EXPECT_GE) { EXPECT_GE(2, 1); EXPECT_GE(2, 2); EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3), "Expected: (2) >= (3), actual: 2 vs 3"); EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1), "(0.9) >= (1.1)"); } // Tests EXPECT_GT. TEST(ExpectTest, EXPECT_GT) { EXPECT_GT(2, 1); EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2), "Expected: (2) > (2), actual: 2 vs 2"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3), "(2) > (3)"); } #if GTEST_HAS_EXCEPTIONS // Tests EXPECT_THROW. TEST(ExpectTest, EXPECT_THROW) { EXPECT_THROW(ThrowAnInteger(), int); EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), "Expected: ThrowAnInteger() throws an exception of " "type bool.\n Actual: it throws a different type."); EXPECT_NONFATAL_FAILURE( EXPECT_THROW(ThrowNothing(), bool), "Expected: ThrowNothing() throws an exception of type bool.\n" " Actual: it throws nothing."); } // Tests EXPECT_NO_THROW. TEST(ExpectTest, EXPECT_NO_THROW) { EXPECT_NO_THROW(ThrowNothing()); EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()), "Expected: ThrowAnInteger() doesn't throw an " "exception.\n Actual: it throws."); } // Tests EXPECT_ANY_THROW. TEST(ExpectTest, EXPECT_ANY_THROW) { EXPECT_ANY_THROW(ThrowAnInteger()); EXPECT_NONFATAL_FAILURE( EXPECT_ANY_THROW(ThrowNothing()), "Expected: ThrowNothing() throws an exception.\n" " Actual: it doesn't."); } #endif // GTEST_HAS_EXCEPTIONS // Make sure we deal with the precedence of <<. TEST(ExpectTest, ExpectPrecedence) { EXPECT_EQ(1 < 2, true); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false), "Value of: true && false"); } // Tests the StreamableToString() function. // Tests using StreamableToString() on a scalar. TEST(StreamableToStringTest, Scalar) { EXPECT_STREQ("5", StreamableToString(5).c_str()); } // Tests using StreamableToString() on a non-char pointer. TEST(StreamableToStringTest, Pointer) { int n = 0; int* p = &n; EXPECT_STRNE("(null)", StreamableToString(p).c_str()); } // Tests using StreamableToString() on a NULL non-char pointer. TEST(StreamableToStringTest, NullPointer) { int* p = NULL; EXPECT_STREQ("(null)", StreamableToString(p).c_str()); } // Tests using StreamableToString() on a C string. TEST(StreamableToStringTest, CString) { EXPECT_STREQ("Foo", StreamableToString("Foo").c_str()); } // Tests using StreamableToString() on a NULL C string. TEST(StreamableToStringTest, NullCString) { char* p = NULL; EXPECT_STREQ("(null)", StreamableToString(p).c_str()); } // Tests using streamable values as assertion messages. // Tests using std::string as an assertion message. TEST(StreamableTest, string) { static const std::string str( "This failure message is a std::string, and is expected."); EXPECT_FATAL_FAILURE(FAIL() << str, str.c_str()); } // Tests that we can output strings containing embedded NULs. // Limited to Linux because we can only do this with std::string's. TEST(StreamableTest, stringWithEmbeddedNUL) { static const char char_array_with_nul[] = "Here's a NUL\0 and some more string"; static const std::string string_with_nul(char_array_with_nul, sizeof(char_array_with_nul) - 1); // drops the trailing NUL EXPECT_FATAL_FAILURE(FAIL() << string_with_nul, "Here's a NUL\\0 and some more string"); } // Tests that we can output a NUL char. TEST(StreamableTest, NULChar) { EXPECT_FATAL_FAILURE({ // NOLINT FAIL() << "A NUL" << '\0' << " and some more string"; }, "A NUL\\0 and some more string"); } // Tests using int as an assertion message. TEST(StreamableTest, int) { EXPECT_FATAL_FAILURE(FAIL() << 900913, "900913"); } // Tests using NULL char pointer as an assertion message. // // In MSVC, streaming a NULL char * causes access violation. Google Test // implemented a workaround (substituting "(null)" for NULL). This // tests whether the workaround works. TEST(StreamableTest, NullCharPtr) { EXPECT_FATAL_FAILURE(FAIL() << static_cast(NULL), "(null)"); } // Tests that basic IO manipulators (endl, ends, and flush) can be // streamed to testing::Message. TEST(StreamableTest, BasicIoManip) { EXPECT_FATAL_FAILURE({ // NOLINT FAIL() << "Line 1." << std::endl << "A NUL char " << std::ends << std::flush << " in line 2."; }, "Line 1.\nA NUL char \\0 in line 2."); } // Tests the macros that haven't been covered so far. void AddFailureHelper(bool* aborted) { *aborted = true; ADD_FAILURE() << "Intentional failure."; *aborted = false; } // Tests ADD_FAILURE. TEST(MacroTest, ADD_FAILURE) { bool aborted = true; EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted), "Intentional failure."); EXPECT_FALSE(aborted); } // Tests ADD_FAILURE_AT. TEST(MacroTest, ADD_FAILURE_AT) { // Verifies that ADD_FAILURE_AT does generate a nonfatal failure and // the failure message contains the user-streamed part. EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42) << "Wrong!", "Wrong!"); // Verifies that the user-streamed part is optional. EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42), "Failed"); // Unfortunately, we cannot verify that the failure message contains // the right file path and line number the same way, as // EXPECT_NONFATAL_FAILURE() doesn't get to see the file path and // line number. Instead, we do that in gtest_output_test_.cc. } // Tests FAIL. TEST(MacroTest, FAIL) { EXPECT_FATAL_FAILURE(FAIL(), "Failed"); EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.", "Intentional failure."); } // Tests SUCCEED TEST(MacroTest, SUCCEED) { SUCCEED(); SUCCEED() << "Explicit success."; } // Tests for EXPECT_EQ() and ASSERT_EQ(). // // These tests fail *intentionally*, s.t. the failure messages can be // generated and tested. // // We have different tests for different argument types. // Tests using bool values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Bool) { EXPECT_EQ(true, true); EXPECT_FATAL_FAILURE({ bool false_value = false; ASSERT_EQ(false_value, true); }, "Value of: true"); } // Tests using int values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Int) { ASSERT_EQ(32, 32); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33), "33"); } // Tests using time_t values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Time_T) { EXPECT_EQ(static_cast(0), static_cast(0)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0), static_cast(1234)), "1234"); } // Tests using char values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, Char) { ASSERT_EQ('z', 'z'); const char ch = 'b'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch), "ch"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch), "ch"); } // Tests using wchar_t values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, WideChar) { EXPECT_EQ(L'b', L'b'); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'), "Value of: L'x'\n" " Actual: L'x' (120, 0x78)\n" "Expected: L'\0'\n" "Which is: L'\0' (0, 0x0)"); static wchar_t wchar; wchar = L'b'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar), "wchar"); wchar = 0x8119; EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0x8120), wchar), "Value of: wchar"); } // Tests using ::std::string values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, StdString) { // Compares a const char* to an std::string that has identical // content. ASSERT_EQ("Test", ::std::string("Test")); // Compares two identical std::strings. static const ::std::string str1("A * in the middle"); static const ::std::string str2(str1); EXPECT_EQ(str1, str2); // Compares a const char* to an std::string that has different // content EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")), "\"test\""); // Compares an std::string to a char* that has different content. char* const p1 = const_cast("foo"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1), "p1"); // Compares two std::strings that have different contents, one of // which having a NUL character in the middle. This should fail. static ::std::string str3(str1); str3.at(2) = '\0'; EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3), "Value of: str3\n" " Actual: \"A \\0 in the middle\""); } #if GTEST_HAS_STD_WSTRING // Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, StdWideString) { // Compares two identical std::wstrings. const ::std::wstring wstr1(L"A * in the middle"); const ::std::wstring wstr2(wstr1); ASSERT_EQ(wstr1, wstr2); // Compares an std::wstring to a const wchar_t* that has identical // content. const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; EXPECT_EQ(::std::wstring(kTestX8119), kTestX8119); // Compares an std::wstring to a const wchar_t* that has different // content. const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(::std::wstring(kTestX8119), kTestX8120); }, "kTestX8120"); // Compares two std::wstrings that have different contents, one of // which having a NUL character in the middle. ::std::wstring wstr3(wstr1); wstr3.at(2) = L'\0'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3), "wstr3"); // Compares a wchar_t* to an std::wstring that has different // content. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(const_cast(L"foo"), ::std::wstring(L"bar")); }, ""); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_STRING // Tests using ::string values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, GlobalString) { // Compares a const char* to a ::string that has identical content. EXPECT_EQ("Test", ::string("Test")); // Compares two identical ::strings. const ::string str1("A * in the middle"); const ::string str2(str1); ASSERT_EQ(str1, str2); // Compares a ::string to a const char* that has different content. EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::string("Test"), "test"), "test"); // Compares two ::strings that have different contents, one of which // having a NUL character in the middle. ::string str3(str1); str3.at(2) = '\0'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(str1, str3), "str3"); // Compares a ::string to a char* that has different content. EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(::string("bar"), const_cast("foo")); }, ""); } #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING // Tests using ::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, GlobalWideString) { // Compares two identical ::wstrings. static const ::wstring wstr1(L"A * in the middle"); static const ::wstring wstr2(wstr1); EXPECT_EQ(wstr1, wstr2); // Compares a const wchar_t* to a ::wstring that has identical content. const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; ASSERT_EQ(kTestX8119, ::wstring(kTestX8119)); // Compares a const wchar_t* to a ::wstring that has different // content. const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(kTestX8120, ::wstring(kTestX8119)); }, "Test\\x8119"); // Compares a wchar_t* to a ::wstring that has different content. wchar_t* const p1 = const_cast(L"foo"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, ::wstring(L"bar")), "bar"); // Compares two ::wstrings that have different contents, one of which // having a NUL character in the middle. static ::wstring wstr3; wstr3 = wstr1; wstr3.at(2) = L'\0'; EXPECT_FATAL_FAILURE(ASSERT_EQ(wstr1, wstr3), "wstr3"); } #endif // GTEST_HAS_GLOBAL_WSTRING // Tests using char pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, CharPointer) { char* const p0 = NULL; // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT void* pv2 = (void*)0xABC0; // NOLINT char* const p1 = reinterpret_cast(pv1); char* const p2 = reinterpret_cast(pv2); ASSERT_EQ(p1, p1); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "Value of: p2"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), "p2"); EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast(0x1234), reinterpret_cast(0xABC0)), "ABC0"); } // Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, WideCharPointer) { wchar_t* const p0 = NULL; // Only way to get the Nokia compiler to compile the cast // is to have a separate void* variable first. Putting // the two casts on the same line doesn't work, neither does // a direct C-style to char*. void* pv1 = (void*)0x1234; // NOLINT void* pv2 = (void*)0xABC0; // NOLINT wchar_t* const p1 = reinterpret_cast(pv1); wchar_t* const p2 = reinterpret_cast(pv2); EXPECT_EQ(p0, p0); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "Value of: p2"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), "p2"); void* pv3 = (void*)0x1234; // NOLINT void* pv4 = (void*)0xABC0; // NOLINT const wchar_t* p3 = reinterpret_cast(pv3); const wchar_t* p4 = reinterpret_cast(pv4); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4), "p4"); } // Tests using other types of pointers in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, OtherPointer) { ASSERT_EQ(static_cast(NULL), static_cast(NULL)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(NULL), reinterpret_cast(0x1234)), "0x1234"); } // A class that supports binary comparison operators but not streaming. class UnprintableChar { public: explicit UnprintableChar(char ch) : char_(ch) {} bool operator==(const UnprintableChar& rhs) const { return char_ == rhs.char_; } bool operator!=(const UnprintableChar& rhs) const { return char_ != rhs.char_; } bool operator<(const UnprintableChar& rhs) const { return char_ < rhs.char_; } bool operator<=(const UnprintableChar& rhs) const { return char_ <= rhs.char_; } bool operator>(const UnprintableChar& rhs) const { return char_ > rhs.char_; } bool operator>=(const UnprintableChar& rhs) const { return char_ >= rhs.char_; } private: char char_; }; // Tests that ASSERT_EQ() and friends don't require the arguments to // be printable. TEST(ComparisonAssertionTest, AcceptsUnprintableArgs) { const UnprintableChar x('x'), y('y'); ASSERT_EQ(x, x); EXPECT_NE(x, y); ASSERT_LT(x, y); EXPECT_LE(x, y); ASSERT_GT(y, x); EXPECT_GE(x, x); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <78>"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <79>"); EXPECT_NONFATAL_FAILURE(EXPECT_LT(y, y), "1-byte object <79>"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <78>"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <79>"); // Code tested by EXPECT_FATAL_FAILURE cannot reference local // variables, so we have to write UnprintableChar('x') instead of x. #ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_NE(UnprintableChar('x'), UnprintableChar('x')), "1-byte object <78>"); EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), "1-byte object <78>"); #endif EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), "1-byte object <79>"); EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), "1-byte object <78>"); EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), "1-byte object <79>"); } // Tests the FRIEND_TEST macro. // This class has a private member we want to test. We will test it // both in a TEST and in a TEST_F. class Foo { public: Foo() {} private: int Bar() const { return 1; } // Declares the friend tests that can access the private member // Bar(). FRIEND_TEST(FRIEND_TEST_Test, TEST); FRIEND_TEST(FRIEND_TEST_Test2, TEST_F); }; // Tests that the FRIEND_TEST declaration allows a TEST to access a // class's private members. This should compile. TEST(FRIEND_TEST_Test, TEST) { ASSERT_EQ(1, Foo().Bar()); } // The fixture needed to test using FRIEND_TEST with TEST_F. class FRIEND_TEST_Test2 : public Test { protected: Foo foo; }; // Tests that the FRIEND_TEST declaration allows a TEST_F to access a // class's private members. This should compile. TEST_F(FRIEND_TEST_Test2, TEST_F) { ASSERT_EQ(1, foo.Bar()); } // Tests the life cycle of Test objects. // The test fixture for testing the life cycle of Test objects. // // This class counts the number of live test objects that uses this // fixture. class TestLifeCycleTest : public Test { protected: // Constructor. Increments the number of test objects that uses // this fixture. TestLifeCycleTest() { count_++; } // Destructor. Decrements the number of test objects that uses this // fixture. ~TestLifeCycleTest() { count_--; } // Returns the number of live test objects that uses this fixture. int count() const { return count_; } private: static int count_; }; int TestLifeCycleTest::count_ = 0; // Tests the life cycle of test objects. TEST_F(TestLifeCycleTest, Test1) { // There should be only one test object in this test case that's // currently alive. ASSERT_EQ(1, count()); } // Tests the life cycle of test objects. TEST_F(TestLifeCycleTest, Test2) { // After Test1 is done and Test2 is started, there should still be // only one live test object, as the object for Test1 should've been // deleted. ASSERT_EQ(1, count()); } } // namespace // Tests that the copy constructor works when it is NOT optimized away by // the compiler. TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied) { // Checks that the copy constructor doesn't try to dereference NULL pointers // in the source object. AssertionResult r1 = AssertionSuccess(); AssertionResult r2 = r1; // The following line is added to prevent the compiler from optimizing // away the constructor call. r1 << "abc"; AssertionResult r3 = r1; EXPECT_EQ(static_cast(r3), static_cast(r1)); EXPECT_STREQ("abc", r1.message()); } // Tests that AssertionSuccess and AssertionFailure construct // AssertionResult objects as expected. TEST(AssertionResultTest, ConstructionWorks) { AssertionResult r1 = AssertionSuccess(); EXPECT_TRUE(r1); EXPECT_STREQ("", r1.message()); AssertionResult r2 = AssertionSuccess() << "abc"; EXPECT_TRUE(r2); EXPECT_STREQ("abc", r2.message()); AssertionResult r3 = AssertionFailure(); EXPECT_FALSE(r3); EXPECT_STREQ("", r3.message()); AssertionResult r4 = AssertionFailure() << "def"; EXPECT_FALSE(r4); EXPECT_STREQ("def", r4.message()); AssertionResult r5 = AssertionFailure(Message() << "ghi"); EXPECT_FALSE(r5); EXPECT_STREQ("ghi", r5.message()); } // Tests that the negation flips the predicate result but keeps the message. TEST(AssertionResultTest, NegationWorks) { AssertionResult r1 = AssertionSuccess() << "abc"; EXPECT_FALSE(!r1); EXPECT_STREQ("abc", (!r1).message()); AssertionResult r2 = AssertionFailure() << "def"; EXPECT_TRUE(!r2); EXPECT_STREQ("def", (!r2).message()); } TEST(AssertionResultTest, StreamingWorks) { AssertionResult r = AssertionSuccess(); r << "abc" << 'd' << 0 << true; EXPECT_STREQ("abcd0true", r.message()); } TEST(AssertionResultTest, CanStreamOstreamManipulators) { AssertionResult r = AssertionSuccess(); r << "Data" << std::endl << std::flush << std::ends << "Will be visible"; EXPECT_STREQ("Data\n\\0Will be visible", r.message()); } // Tests streaming a user type whose definition and operator << are // both in the global namespace. class Base { public: explicit Base(int an_x) : x_(an_x) {} int x() const { return x_; } private: int x_; }; std::ostream& operator<<(std::ostream& os, const Base& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const Base* pointer) { return os << "(" << pointer->x() << ")"; } TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace) { Message msg; Base a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition and operator<< are // both in an unnamed namespace. namespace { class MyTypeInUnnamedNameSpace : public Base { public: explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {} }; std::ostream& operator<<(std::ostream& os, const MyTypeInUnnamedNameSpace& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const MyTypeInUnnamedNameSpace* pointer) { return os << "(" << pointer->x() << ")"; } } // namespace TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace) { Message msg; MyTypeInUnnamedNameSpace a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition and operator<< are // both in a user namespace. namespace namespace1 { class MyTypeInNameSpace1 : public Base { public: explicit MyTypeInNameSpace1(int an_x): Base(an_x) {} }; std::ostream& operator<<(std::ostream& os, const MyTypeInNameSpace1& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const MyTypeInNameSpace1* pointer) { return os << "(" << pointer->x() << ")"; } } // namespace namespace1 TEST(MessageTest, CanStreamUserTypeInUserNameSpace) { Message msg; namespace1::MyTypeInNameSpace1 a(1); msg << a << &a; // Uses namespace1::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming a user type whose definition is in a user namespace // but whose operator<< is in the global namespace. namespace namespace2 { class MyTypeInNameSpace2 : public ::Base { public: explicit MyTypeInNameSpace2(int an_x): Base(an_x) {} }; } // namespace namespace2 std::ostream& operator<<(std::ostream& os, const namespace2::MyTypeInNameSpace2& val) { return os << val.x(); } std::ostream& operator<<(std::ostream& os, const namespace2::MyTypeInNameSpace2* pointer) { return os << "(" << pointer->x() << ")"; } TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal) { Message msg; namespace2::MyTypeInNameSpace2 a(1); msg << a << &a; // Uses ::operator<<. EXPECT_STREQ("1(1)", msg.GetString().c_str()); } // Tests streaming NULL pointers to testing::Message. TEST(MessageTest, NullPointers) { Message msg; char* const p1 = NULL; unsigned char* const p2 = NULL; int* p3 = NULL; double* p4 = NULL; bool* p5 = NULL; Message* p6 = NULL; msg << p1 << p2 << p3 << p4 << p5 << p6; ASSERT_STREQ("(null)(null)(null)(null)(null)(null)", msg.GetString().c_str()); } // Tests streaming wide strings to testing::Message. TEST(MessageTest, WideStrings) { // Streams a NULL of type const wchar_t*. const wchar_t* const_wstr = NULL; EXPECT_STREQ("(null)", (Message() << const_wstr).GetString().c_str()); // Streams a NULL of type wchar_t*. wchar_t* wstr = NULL; EXPECT_STREQ("(null)", (Message() << wstr).GetString().c_str()); // Streams a non-NULL of type const wchar_t*. const_wstr = L"abc\x8119"; EXPECT_STREQ("abc\xe8\x84\x99", (Message() << const_wstr).GetString().c_str()); // Streams a non-NULL of type wchar_t*. wstr = const_cast(const_wstr); EXPECT_STREQ("abc\xe8\x84\x99", (Message() << wstr).GetString().c_str()); } // This line tests that we can define tests in the testing namespace. namespace testing { // Tests the TestInfo class. class TestInfoTest : public Test { protected: static const TestInfo* GetTestInfo(const char* test_name) { const TestCase* const test_case = GetUnitTestImpl()-> GetTestCase("TestInfoTest", "", NULL, NULL); for (int i = 0; i < test_case->total_test_count(); ++i) { const TestInfo* const test_info = test_case->GetTestInfo(i); if (strcmp(test_name, test_info->name()) == 0) return test_info; } return NULL; } static const TestResult* GetTestResult( const TestInfo* test_info) { return test_info->result(); } }; // Tests TestInfo::test_case_name() and TestInfo::name(). TEST_F(TestInfoTest, Names) { const TestInfo* const test_info = GetTestInfo("Names"); ASSERT_STREQ("TestInfoTest", test_info->test_case_name()); ASSERT_STREQ("Names", test_info->name()); } // Tests TestInfo::result(). TEST_F(TestInfoTest, result) { const TestInfo* const test_info = GetTestInfo("result"); // Initially, there is no TestPartResult for this test. ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); // After the previous assertion, there is still none. ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); } // Tests setting up and tearing down a test case. class SetUpTestCaseTest : public Test { protected: // This will be called once before the first test in this test case // is run. static void SetUpTestCase() { printf("Setting up the test case . . .\n"); // Initializes some shared resource. In this simple example, we // just create a C string. More complex stuff can be done if // desired. shared_resource_ = "123"; // Increments the number of test cases that have been set up. counter_++; // SetUpTestCase() should be called only once. EXPECT_EQ(1, counter_); } // This will be called once after the last test in this test case is // run. static void TearDownTestCase() { printf("Tearing down the test case . . .\n"); // Decrements the number of test cases that have been set up. counter_--; // TearDownTestCase() should be called only once. EXPECT_EQ(0, counter_); // Cleans up the shared resource. shared_resource_ = NULL; } // This will be called before each test in this test case. virtual void SetUp() { // SetUpTestCase() should be called only once, so counter_ should // always be 1. EXPECT_EQ(1, counter_); } // Number of test cases that have been set up. static int counter_; // Some resource to be shared by all tests in this test case. static const char* shared_resource_; }; int SetUpTestCaseTest::counter_ = 0; const char* SetUpTestCaseTest::shared_resource_ = NULL; // A test that uses the shared resource. TEST_F(SetUpTestCaseTest, Test1) { EXPECT_STRNE(NULL, shared_resource_); } // Another test that uses the shared resource. TEST_F(SetUpTestCaseTest, Test2) { EXPECT_STREQ("123", shared_resource_); } // The InitGoogleTestTest test case tests testing::InitGoogleTest(). // The Flags struct stores a copy of all Google Test flags. struct Flags { // Constructs a Flags struct where each flag has its default value. Flags() : also_run_disabled_tests(false), break_on_failure(false), catch_exceptions(false), death_test_use_fork(false), filter(""), list_tests(false), output(""), print_time(true), random_seed(0), repeat(1), shuffle(false), stack_trace_depth(kMaxStackTraceDepth), stream_result_to(""), throw_on_failure(false) {} // Factory methods. // Creates a Flags struct where the gtest_also_run_disabled_tests flag has // the given value. static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) { Flags flags; flags.also_run_disabled_tests = also_run_disabled_tests; return flags; } // Creates a Flags struct where the gtest_break_on_failure flag has // the given value. static Flags BreakOnFailure(bool break_on_failure) { Flags flags; flags.break_on_failure = break_on_failure; return flags; } // Creates a Flags struct where the gtest_catch_exceptions flag has // the given value. static Flags CatchExceptions(bool catch_exceptions) { Flags flags; flags.catch_exceptions = catch_exceptions; return flags; } // Creates a Flags struct where the gtest_death_test_use_fork flag has // the given value. static Flags DeathTestUseFork(bool death_test_use_fork) { Flags flags; flags.death_test_use_fork = death_test_use_fork; return flags; } // Creates a Flags struct where the gtest_filter flag has the given // value. static Flags Filter(const char* filter) { Flags flags; flags.filter = filter; return flags; } // Creates a Flags struct where the gtest_list_tests flag has the // given value. static Flags ListTests(bool list_tests) { Flags flags; flags.list_tests = list_tests; return flags; } // Creates a Flags struct where the gtest_output flag has the given // value. static Flags Output(const char* output) { Flags flags; flags.output = output; return flags; } // Creates a Flags struct where the gtest_print_time flag has the given // value. static Flags PrintTime(bool print_time) { Flags flags; flags.print_time = print_time; return flags; } // Creates a Flags struct where the gtest_random_seed flag has // the given value. static Flags RandomSeed(Int32 random_seed) { Flags flags; flags.random_seed = random_seed; return flags; } // Creates a Flags struct where the gtest_repeat flag has the given // value. static Flags Repeat(Int32 repeat) { Flags flags; flags.repeat = repeat; return flags; } // Creates a Flags struct where the gtest_shuffle flag has // the given value. static Flags Shuffle(bool shuffle) { Flags flags; flags.shuffle = shuffle; return flags; } // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has // the given value. static Flags StackTraceDepth(Int32 stack_trace_depth) { Flags flags; flags.stack_trace_depth = stack_trace_depth; return flags; } // Creates a Flags struct where the GTEST_FLAG(stream_result_to) flag has // the given value. static Flags StreamResultTo(const char* stream_result_to) { Flags flags; flags.stream_result_to = stream_result_to; return flags; } // Creates a Flags struct where the gtest_throw_on_failure flag has // the given value. static Flags ThrowOnFailure(bool throw_on_failure) { Flags flags; flags.throw_on_failure = throw_on_failure; return flags; } // These fields store the flag values. bool also_run_disabled_tests; bool break_on_failure; bool catch_exceptions; bool death_test_use_fork; const char* filter; bool list_tests; const char* output; bool print_time; Int32 random_seed; Int32 repeat; bool shuffle; Int32 stack_trace_depth; const char* stream_result_to; bool throw_on_failure; }; // Fixture for testing InitGoogleTest(). class InitGoogleTestTest : public Test { protected: // Clears the flags before each test. virtual void SetUp() { GTEST_FLAG(also_run_disabled_tests) = false; GTEST_FLAG(break_on_failure) = false; GTEST_FLAG(catch_exceptions) = false; GTEST_FLAG(death_test_use_fork) = false; GTEST_FLAG(filter) = ""; GTEST_FLAG(list_tests) = false; GTEST_FLAG(output) = ""; GTEST_FLAG(print_time) = true; GTEST_FLAG(random_seed) = 0; GTEST_FLAG(repeat) = 1; GTEST_FLAG(shuffle) = false; GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; GTEST_FLAG(stream_result_to) = ""; GTEST_FLAG(throw_on_failure) = false; } // Asserts that two narrow or wide string arrays are equal. template static void AssertStringArrayEq(size_t size1, CharType** array1, size_t size2, CharType** array2) { ASSERT_EQ(size1, size2) << " Array sizes different."; for (size_t i = 0; i != size1; i++) { ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i; } } // Verifies that the flag values match the expected values. static void CheckFlags(const Flags& expected) { EXPECT_EQ(expected.also_run_disabled_tests, GTEST_FLAG(also_run_disabled_tests)); EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure)); EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions)); EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork)); EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str()); EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests)); EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str()); EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time)); EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed)); EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat)); EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle)); EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth)); EXPECT_STREQ(expected.stream_result_to, GTEST_FLAG(stream_result_to).c_str()); EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure)); } // Parses a command line (specified by argc1 and argv1), then // verifies that the flag values are expected and that the // recognized flags are removed from the command line. template static void TestParsingFlags(int argc1, const CharType** argv1, int argc2, const CharType** argv2, const Flags& expected, bool should_print_help) { const bool saved_help_flag = ::testing::internal::g_help_flag; ::testing::internal::g_help_flag = false; #if GTEST_HAS_STREAM_REDIRECTION CaptureStdout(); #endif // Parses the command line. internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); #if GTEST_HAS_STREAM_REDIRECTION const std::string captured_stdout = GetCapturedStdout(); #endif // Verifies the flag values. CheckFlags(expected); // Verifies that the recognized flags are removed from the command // line. AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2); // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the // help message for the flags it recognizes. EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); #if GTEST_HAS_STREAM_REDIRECTION const char* const expected_help_fragment = "This program contains tests written using"; if (should_print_help) { EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout); } else { EXPECT_PRED_FORMAT2(IsNotSubstring, expected_help_fragment, captured_stdout); } #endif // GTEST_HAS_STREAM_REDIRECTION ::testing::internal::g_help_flag = saved_help_flag; } // This macro wraps TestParsingFlags s.t. the user doesn't need // to specify the array sizes. #define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \ TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \ sizeof(argv2)/sizeof(*argv2) - 1, argv2, \ expected, should_print_help) }; // Tests parsing an empty command line. TEST_F(InitGoogleTestTest, Empty) { const char* argv[] = { NULL }; const char* argv2[] = { NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); } // Tests parsing a command line that has no flag. TEST_F(InitGoogleTestTest, NoFlag) { const char* argv[] = { "foo.exe", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); } // Tests parsing a bad --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterBad) { const char* argv[] = { "foo.exe", "--gtest_filter", NULL }; const char* argv2[] = { "foo.exe", "--gtest_filter", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); } // Tests parsing an empty --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterEmpty) { const char* argv[] = { "foo.exe", "--gtest_filter=", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false); } // Tests parsing a non-empty --gtest_filter flag. TEST_F(InitGoogleTestTest, FilterNonEmpty) { const char* argv[] = { "foo.exe", "--gtest_filter=abc", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); } // Tests parsing --gtest_break_on_failure. TEST_F(InitGoogleTestTest, BreakOnFailureWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); } // Tests parsing --gtest_break_on_failure=0. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_0) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing --gtest_break_on_failure=f. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_f) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing --gtest_break_on_failure=F. TEST_F(InitGoogleTestTest, BreakOnFailureFalse_F) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); } // Tests parsing a --gtest_break_on_failure flag that has a "true" // definition. TEST_F(InitGoogleTestTest, BreakOnFailureTrue) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); } // Tests parsing --gtest_catch_exceptions. TEST_F(InitGoogleTestTest, CatchExceptions) { const char* argv[] = { "foo.exe", "--gtest_catch_exceptions", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false); } // Tests parsing --gtest_death_test_use_fork. TEST_F(InitGoogleTestTest, DeathTestUseFork) { const char* argv[] = { "foo.exe", "--gtest_death_test_use_fork", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false); } // Tests having the same flag twice with different values. The // expected behavior is that the one coming last takes precedence. TEST_F(InitGoogleTestTest, DuplicatedFlags) { const char* argv[] = { "foo.exe", "--gtest_filter=a", "--gtest_filter=b", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false); } // Tests having an unrecognized flag on the command line. TEST_F(InitGoogleTestTest, UnrecognizedFlag) { const char* argv[] = { "foo.exe", "--gtest_break_on_failure", "bar", // Unrecognized by Google Test. "--gtest_filter=b", NULL }; const char* argv2[] = { "foo.exe", "bar", NULL }; Flags flags; flags.break_on_failure = true; flags.filter = "b"; GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false); } // Tests having a --gtest_list_tests flag TEST_F(InitGoogleTestTest, ListTestsFlag) { const char* argv[] = { "foo.exe", "--gtest_list_tests", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); } // Tests having a --gtest_list_tests flag with a "true" value TEST_F(InitGoogleTestTest, ListTestsTrue) { const char* argv[] = { "foo.exe", "--gtest_list_tests=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); } // Tests having a --gtest_list_tests flag with a "false" value TEST_F(InitGoogleTestTest, ListTestsFalse) { const char* argv[] = { "foo.exe", "--gtest_list_tests=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_list_tests=f. TEST_F(InitGoogleTestTest, ListTestsFalse_f) { const char* argv[] = { "foo.exe", "--gtest_list_tests=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_list_tests=F. TEST_F(InitGoogleTestTest, ListTestsFalse_F) { const char* argv[] = { "foo.exe", "--gtest_list_tests=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } // Tests parsing --gtest_output (invalid). TEST_F(InitGoogleTestTest, OutputEmpty) { const char* argv[] = { "foo.exe", "--gtest_output", NULL }; const char* argv2[] = { "foo.exe", "--gtest_output", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); } // Tests parsing --gtest_output=xml TEST_F(InitGoogleTestTest, OutputXml) { const char* argv[] = { "foo.exe", "--gtest_output=xml", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false); } // Tests parsing --gtest_output=xml:file TEST_F(InitGoogleTestTest, OutputXmlFile) { const char* argv[] = { "foo.exe", "--gtest_output=xml:file", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false); } // Tests parsing --gtest_output=xml:directory/path/ TEST_F(InitGoogleTestTest, OutputXmlDirectory) { const char* argv[] = { "foo.exe", "--gtest_output=xml:directory/path/", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:directory/path/"), false); } // Tests having a --gtest_print_time flag TEST_F(InitGoogleTestTest, PrintTimeFlag) { const char* argv[] = { "foo.exe", "--gtest_print_time", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); } // Tests having a --gtest_print_time flag with a "true" value TEST_F(InitGoogleTestTest, PrintTimeTrue) { const char* argv[] = { "foo.exe", "--gtest_print_time=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); } // Tests having a --gtest_print_time flag with a "false" value TEST_F(InitGoogleTestTest, PrintTimeFalse) { const char* argv[] = { "foo.exe", "--gtest_print_time=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_print_time=f. TEST_F(InitGoogleTestTest, PrintTimeFalse_f) { const char* argv[] = { "foo.exe", "--gtest_print_time=f", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_print_time=F. TEST_F(InitGoogleTestTest, PrintTimeFalse_F) { const char* argv[] = { "foo.exe", "--gtest_print_time=F", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); } // Tests parsing --gtest_random_seed=number TEST_F(InitGoogleTestTest, RandomSeed) { const char* argv[] = { "foo.exe", "--gtest_random_seed=1000", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false); } // Tests parsing --gtest_repeat=number TEST_F(InitGoogleTestTest, Repeat) { const char* argv[] = { "foo.exe", "--gtest_repeat=1000", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false); } // Tests having a --gtest_also_run_disabled_tests flag TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFlag) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), false); } // Tests having a --gtest_also_run_disabled_tests flag with a "true" value TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsTrue) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), false); } // Tests having a --gtest_also_run_disabled_tests flag with a "false" value TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFalse) { const char* argv[] = { "foo.exe", "--gtest_also_run_disabled_tests=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(false), false); } // Tests parsing --gtest_shuffle. TEST_F(InitGoogleTestTest, ShuffleWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_shuffle", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); } // Tests parsing --gtest_shuffle=0. TEST_F(InitGoogleTestTest, ShuffleFalse_0) { const char* argv[] = { "foo.exe", "--gtest_shuffle=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false); } // Tests parsing a --gtest_shuffle flag that has a "true" // definition. TEST_F(InitGoogleTestTest, ShuffleTrue) { const char* argv[] = { "foo.exe", "--gtest_shuffle=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); } // Tests parsing --gtest_stack_trace_depth=number. TEST_F(InitGoogleTestTest, StackTraceDepth) { const char* argv[] = { "foo.exe", "--gtest_stack_trace_depth=5", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false); } TEST_F(InitGoogleTestTest, StreamResultTo) { const char* argv[] = { "foo.exe", "--gtest_stream_result_to=localhost:1234", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_( argv, argv2, Flags::StreamResultTo("localhost:1234"), false); } // Tests parsing --gtest_throw_on_failure. TEST_F(InitGoogleTestTest, ThrowOnFailureWithoutValue) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); } // Tests parsing --gtest_throw_on_failure=0. TEST_F(InitGoogleTestTest, ThrowOnFailureFalse_0) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure=0", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false); } // Tests parsing a --gtest_throw_on_failure flag that has a "true" // definition. TEST_F(InitGoogleTestTest, ThrowOnFailureTrue) { const char* argv[] = { "foo.exe", "--gtest_throw_on_failure=1", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); } #if GTEST_OS_WINDOWS // Tests parsing wide strings. TEST_F(InitGoogleTestTest, WideStrings) { const wchar_t* argv[] = { L"foo.exe", L"--gtest_filter=Foo*", L"--gtest_list_tests=1", L"--gtest_break_on_failure", L"--non_gtest_flag", NULL }; const wchar_t* argv2[] = { L"foo.exe", L"--non_gtest_flag", NULL }; Flags expected_flags; expected_flags.break_on_failure = true; expected_flags.filter = "Foo*"; expected_flags.list_tests = true; GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); } #endif // GTEST_OS_WINDOWS // Tests current_test_info() in UnitTest. class CurrentTestInfoTest : public Test { protected: // Tests that current_test_info() returns NULL before the first test in // the test case is run. static void SetUpTestCase() { // There should be no tests running at this point. const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); EXPECT_TRUE(test_info == NULL) << "There should be no tests running at this point."; } // Tests that current_test_info() returns NULL after the last test in // the test case has run. static void TearDownTestCase() { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); EXPECT_TRUE(test_info == NULL) << "There should be no tests running at this point."; } }; // Tests that current_test_info() returns TestInfo for currently running // test by checking the expected test name against the actual one. TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestCase) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(NULL != test_info) << "There is a test running so we should have a valid TestInfo."; EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) << "Expected the name of the currently running test case."; EXPECT_STREQ("WorksForFirstTestInATestCase", test_info->name()) << "Expected the name of the currently running test."; } // Tests that current_test_info() returns TestInfo for currently running // test by checking the expected test name against the actual one. We // use this test to see that the TestInfo object actually changed from // the previous invocation. TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestCase) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(NULL != test_info) << "There is a test running so we should have a valid TestInfo."; EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) << "Expected the name of the currently running test case."; EXPECT_STREQ("WorksForSecondTestInATestCase", test_info->name()) << "Expected the name of the currently running test."; } } // namespace testing // These two lines test that we can define tests in a namespace that // has the name "testing" and is nested in another namespace. namespace my_namespace { namespace testing { // Makes sure that TEST knows to use ::testing::Test instead of // ::my_namespace::testing::Test. class Test {}; // Makes sure that an assertion knows to use ::testing::Message instead of // ::my_namespace::testing::Message. class Message {}; // Makes sure that an assertion knows to use // ::testing::AssertionResult instead of // ::my_namespace::testing::AssertionResult. class AssertionResult {}; // Tests that an assertion that should succeed works as expected. TEST(NestedTestingNamespaceTest, Success) { EXPECT_EQ(1, 1) << "This shouldn't fail."; } // Tests that an assertion that should fail works as expected. TEST(NestedTestingNamespaceTest, Failure) { EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.", "This failure is expected."); } } // namespace testing } // namespace my_namespace // Tests that one can call superclass SetUp and TearDown methods-- // that is, that they are not private. // No tests are based on this fixture; the test "passes" if it compiles // successfully. class ProtectedFixtureMethodsTest : public Test { protected: virtual void SetUp() { Test::SetUp(); } virtual void TearDown() { Test::TearDown(); } }; // StreamingAssertionsTest tests the streaming versions of a representative // sample of assertions. TEST(StreamingAssertionsTest, Unconditional) { SUCCEED() << "expected success"; EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(FAIL() << "expected failure", "expected failure"); } #ifdef __BORLANDC__ // Silences warnings: "Condition is always true", "Unreachable code" # pragma option push -w-ccc -w-rch #endif TEST(StreamingAssertionsTest, Truth) { EXPECT_TRUE(true) << "unexpected failure"; ASSERT_TRUE(true) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, Truth2) { EXPECT_FALSE(false) << "unexpected failure"; ASSERT_FALSE(false) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure", "expected failure"); } #ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" supressed them # pragma option pop #endif TEST(StreamingAssertionsTest, IntegerEquals) { EXPECT_EQ(1, 1) << "unexpected failure"; ASSERT_EQ(1, 1) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, IntegerLessThan) { EXPECT_LT(1, 2) << "unexpected failure"; ASSERT_LT(1, 2) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsEqual) { EXPECT_STREQ("foo", "foo") << "unexpected failure"; ASSERT_STREQ("foo", "foo") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsNotEqual) { EXPECT_STRNE("foo", "bar") << "unexpected failure"; ASSERT_STRNE("foo", "bar") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringsEqualIgnoringCase) { EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure"; ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase) { EXPECT_STRCASENE("foo", "bar") << "unexpected failure"; ASSERT_STRCASENE("foo", "bar") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, FloatingPointEquals) { EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure", "expected failure"); } #if GTEST_HAS_EXCEPTIONS TEST(StreamingAssertionsTest, Throw) { EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure"; ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, NoThrow) { EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure"; ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) << "expected failure", "expected failure"); } TEST(StreamingAssertionsTest, AnyThrow) { EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) << "expected failure", "expected failure"); EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) << "expected failure", "expected failure"); } #endif // GTEST_HAS_EXCEPTIONS // Tests that Google Test correctly decides whether to use colors in the output. TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes) { GTEST_FLAG(color) = "yes"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes) { SetEnv("TERM", "dumb"); // TERM doesn't support colors. GTEST_FLAG(color) = "True"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. GTEST_FLAG(color) = "t"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. GTEST_FLAG(color) = "1"; EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo) { GTEST_FLAG(color) = "no"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. } TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid) { SetEnv("TERM", "xterm"); // TERM supports colors. GTEST_FLAG(color) = "F"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. GTEST_FLAG(color) = "0"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. GTEST_FLAG(color) = "unknown"; EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. } TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty) { GTEST_FLAG(color) = "auto"; SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. } TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { GTEST_FLAG(color) = "auto"; #if GTEST_OS_WINDOWS // On Windows, we ignore the TERM variable as it's usually not set. SetEnv("TERM", "dumb"); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", ""); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm"); EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. #else // On non-Windows platforms, we rely on TERM to determine if the // terminal supports colors. SetEnv("TERM", "dumb"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "emacs"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "vt100"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors. EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm-color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "xterm-256color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "screen"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "screen-256color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "linux"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "cygwin"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. #endif // GTEST_OS_WINDOWS } // Verifies that StaticAssertTypeEq works in a namespace scope. static bool dummy1 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); static bool dummy2 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); // Verifies that StaticAssertTypeEq works in a class. template class StaticAssertTypeEqTestHelper { public: StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } }; TEST(StaticAssertTypeEqTest, WorksInClass) { StaticAssertTypeEqTestHelper(); } // Verifies that StaticAssertTypeEq works inside a function. typedef int IntAlias; TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { StaticAssertTypeEq(); StaticAssertTypeEq(); } TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) { testing::UnitTest* const unit_test = testing::UnitTest::GetInstance(); // We don't have a stack walker in Google Test yet. EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str()); EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str()); } TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) { EXPECT_FALSE(HasNonfatalFailure()); } static void FailFatally() { FAIL(); } TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) { FailFatally(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_FALSE(has_nonfatal_failure); } TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { FailFatally(); ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } // A wrapper for calling HasNonfatalFailure outside of a test body. static bool HasNonfatalFailureHelper() { return testing::Test::HasNonfatalFailure(); } TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) { EXPECT_FALSE(HasNonfatalFailureHelper()); } TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) { ADD_FAILURE(); const bool has_nonfatal_failure = HasNonfatalFailureHelper(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_nonfatal_failure); } TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) { EXPECT_FALSE(HasFailure()); } TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) { FailFatally(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { ADD_FAILURE(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { FailFatally(); ADD_FAILURE(); const bool has_failure = HasFailure(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } // A wrapper for calling HasFailure outside of a test body. static bool HasFailureHelper() { return testing::Test::HasFailure(); } TEST(HasFailureTest, WorksOutsideOfTestBody) { EXPECT_FALSE(HasFailureHelper()); } TEST(HasFailureTest, WorksOutsideOfTestBody2) { ADD_FAILURE(); const bool has_failure = HasFailureHelper(); ClearCurrentTestPartResults(); EXPECT_TRUE(has_failure); } class TestListener : public EmptyTestEventListener { public: TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {} TestListener(int* on_start_counter, bool* is_destroyed) : on_start_counter_(on_start_counter), is_destroyed_(is_destroyed) {} virtual ~TestListener() { if (is_destroyed_) *is_destroyed_ = true; } protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { if (on_start_counter_ != NULL) (*on_start_counter_)++; } private: int* on_start_counter_; bool* is_destroyed_; }; // Tests the constructor. TEST(TestEventListenersTest, ConstructionWorks) { TestEventListeners listeners; EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_TRUE(listeners.default_xml_generator() == NULL); } // Tests that the TestEventListeners destructor deletes all the listeners it // owns. TEST(TestEventListenersTest, DestructionWorks) { bool default_result_printer_is_destroyed = false; bool default_xml_printer_is_destroyed = false; bool extra_listener_is_destroyed = false; TestListener* default_result_printer = new TestListener( NULL, &default_result_printer_is_destroyed); TestListener* default_xml_printer = new TestListener( NULL, &default_xml_printer_is_destroyed); TestListener* extra_listener = new TestListener( NULL, &extra_listener_is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, default_result_printer); TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, default_xml_printer); listeners.Append(extra_listener); } EXPECT_TRUE(default_result_printer_is_destroyed); EXPECT_TRUE(default_xml_printer_is_destroyed); EXPECT_TRUE(extra_listener_is_destroyed); } // Tests that a listener Append'ed to a TestEventListeners list starts // receiving events. TEST(TestEventListenersTest, Append) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; listeners.Append(listener); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } EXPECT_TRUE(is_destroyed); } // Tests that listeners receive events in the order they were appended to // the list, except for *End requests, which must be received in the reverse // order. class SequenceTestingListener : public EmptyTestEventListener { public: SequenceTestingListener(std::vector* vector, const char* id) : vector_(vector), id_(id) {} protected: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) { vector_->push_back(GetEventDescription("OnTestProgramStart")); } virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) { vector_->push_back(GetEventDescription("OnTestProgramEnd")); } virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) { vector_->push_back(GetEventDescription("OnTestIterationStart")); } virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) { vector_->push_back(GetEventDescription("OnTestIterationEnd")); } private: std::string GetEventDescription(const char* method) { Message message; message << id_ << "." << method; return message.GetString(); } std::vector* vector_; const char* const id_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); }; TEST(EventListenerTest, AppendKeepsOrder) { std::vector vec; TestEventListeners listeners; listeners.Append(new SequenceTestingListener(&vec, "1st")); listeners.Append(new SequenceTestingListener(&vec, "2nd")); listeners.Append(new SequenceTestingListener(&vec, "3rd")); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str()); EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd( *UnitTest::GetInstance()); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str()); EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart( *UnitTest::GetInstance(), 0); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str()); EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str()); vec.clear(); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd( *UnitTest::GetInstance(), 0); ASSERT_EQ(3U, vec.size()); EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str()); EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str()); EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str()); } // Tests that a listener removed from a TestEventListeners list stops receiving // events and is not deleted when the list is destroyed. TEST(TestEventListenersTest, Release) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; listeners.Append(listener); EXPECT_EQ(listener, listeners.Release(listener)); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_TRUE(listeners.Release(listener) == NULL); } EXPECT_EQ(0, on_start_counter); EXPECT_FALSE(is_destroyed); delete listener; } // Tests that no events are forwarded when event forwarding is disabled. TEST(EventListenerTest, SuppressEventForwarding) { int on_start_counter = 0; TestListener* listener = new TestListener(&on_start_counter, NULL); TestEventListeners listeners; listeners.Append(listener); ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); TestEventListenersAccessor::SuppressEventForwarding(&listeners); ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Tests that events generated by Google Test are not forwarded in // death test subprocesses. TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { EXPECT_DEATH_IF_SUPPORTED({ GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled( *GetUnitTestImpl()->listeners())) << "expected failure";}, "expected failure"); } // Tests that a listener installed via SetDefaultResultPrinter() starts // receiving events and is returned via default_result_printer() and that // the previous default_result_printer is removed from the list and deleted. TEST(EventListenerTest, default_result_printer) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); EXPECT_EQ(listener, listeners.default_result_printer()); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); // Replacing default_result_printer with something else should remove it // from the list and destroy it. TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_TRUE(is_destroyed); // After broadcasting an event the counter is still the same, indicating // the listener is not in the list anymore. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } // Tests that the default_result_printer listener stops receiving events // when removed via Release and that is not owned by the list anymore. TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); EXPECT_EQ(listener, listeners.Release(listener)); EXPECT_TRUE(listeners.default_result_printer() == NULL); EXPECT_FALSE(is_destroyed); // Broadcasting events now should not affect default_result_printer. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Destroying the list should not affect the listener now, too. EXPECT_FALSE(is_destroyed); delete listener; } // Tests that a listener installed via SetDefaultXmlGenerator() starts // receiving events and is returned via default_xml_generator() and that // the previous default_xml_generator is removed from the list and deleted. TEST(EventListenerTest, default_xml_generator) { int on_start_counter = 0; bool is_destroyed = false; TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); TestEventListeners listeners; TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); EXPECT_EQ(listener, listeners.default_xml_generator()); TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); // Replacing default_xml_generator with something else should remove it // from the list and destroy it. TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL); EXPECT_TRUE(listeners.default_xml_generator() == NULL); EXPECT_TRUE(is_destroyed); // After broadcasting an event the counter is still the same, indicating // the listener is not in the list anymore. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(1, on_start_counter); } // Tests that the default_xml_generator listener stops receiving events // when removed via Release and that is not owned by the list anymore. TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) { int on_start_counter = 0; bool is_destroyed = false; // Although Append passes the ownership of this object to the list, // the following calls release it, and we need to delete it before the // test ends. TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); { TestEventListeners listeners; TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); EXPECT_EQ(listener, listeners.Release(listener)); EXPECT_TRUE(listeners.default_xml_generator() == NULL); EXPECT_FALSE(is_destroyed); // Broadcasting events now should not affect default_xml_generator. TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( *UnitTest::GetInstance()); EXPECT_EQ(0, on_start_counter); } // Destroying the list should not affect the listener now, too. EXPECT_FALSE(is_destroyed); delete listener; } // Sanity tests to ensure that the alternative, verbose spellings of // some of the macros work. We don't test them thoroughly as that // would be quite involved. Since their implementations are // straightforward, and they are rarely used, we'll just rely on the // users to tell us when they are broken. GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED. // GTEST_FAIL is the same as FAIL. EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure", "An expected failure"); // GTEST_ASSERT_XY is the same as ASSERT_XY. GTEST_ASSERT_EQ(0, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(0, 1) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_NE(0, 1); GTEST_ASSERT_NE(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_NE(0, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_LE(0, 0); GTEST_ASSERT_LE(0, 1); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LE(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_LT(0, 1); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(0, 0) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_GE(0, 0); GTEST_ASSERT_GE(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GE(0, 1) << "An expected failure", "An expected failure"); GTEST_ASSERT_GT(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(0, 1) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(1, 1) << "An expected failure", "An expected failure"); } // Tests for internal utilities necessary for implementation of the universal // printing. // TODO(vladl@google.com): Find a better home for them. class ConversionHelperBase {}; class ConversionHelperDerived : public ConversionHelperBase {}; // Tests that IsAProtocolMessage::value is a compile-time constant. TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { GTEST_COMPILE_ASSERT_(IsAProtocolMessage::value, const_true); GTEST_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); } // Tests that IsAProtocolMessage::value is true when T is // proto2::Message or a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); EXPECT_TRUE(IsAProtocolMessage::value); } // Tests that IsAProtocolMessage::value is false when T is neither // ProtocolMessage nor a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { EXPECT_FALSE(IsAProtocolMessage::value); EXPECT_FALSE(IsAProtocolMessage::value); } // Tests that CompileAssertTypesEqual compiles when the type arguments are // equal. TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { CompileAssertTypesEqual(); CompileAssertTypesEqual(); } // Tests that RemoveReference does not affect non-reference types. TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that RemoveReference removes reference from reference types. TEST(RemoveReferenceTest, RemovesReference) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_REMOVE_REFERENCE_. template void TestGTestRemoveReference() { CompileAssertTypesEqual(); } TEST(RemoveReferenceTest, MacroVersion) { TestGTestRemoveReference(); TestGTestRemoveReference(); } // Tests that RemoveConst does not affect non-const types. TEST(RemoveConstTest, DoesNotAffectNonConstType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that RemoveConst removes const from const types. TEST(RemoveConstTest, RemovesConst) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_REMOVE_CONST_. template void TestGTestRemoveConst() { CompileAssertTypesEqual(); } TEST(RemoveConstTest, MacroVersion) { TestGTestRemoveConst(); TestGTestRemoveConst(); TestGTestRemoveConst(); } // Tests GTEST_REMOVE_REFERENCE_AND_CONST_. template void TestGTestRemoveReferenceAndConst() { CompileAssertTypesEqual(); } TEST(RemoveReferenceToConstTest, Works) { TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); } // Tests that AddReference does not affect reference types. TEST(AddReferenceTest, DoesNotAffectReferenceType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that AddReference adds reference to non-reference types. TEST(AddReferenceTest, AddsReference) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_ADD_REFERENCE_. template void TestGTestAddReference() { CompileAssertTypesEqual(); } TEST(AddReferenceTest, MacroVersion) { TestGTestAddReference(); TestGTestAddReference(); } // Tests GTEST_REFERENCE_TO_CONST_. template void TestGTestReferenceToConst() { CompileAssertTypesEqual(); } TEST(GTestReferenceToConstTest, Works) { TestGTestReferenceToConst(); TestGTestReferenceToConst(); TestGTestReferenceToConst(); TestGTestReferenceToConst(); } // Tests that ImplicitlyConvertible::value is a compile-time constant. TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { GTEST_COMPILE_ASSERT_((ImplicitlyConvertible::value), const_true); GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible::value), const_false); } // Tests that ImplicitlyConvertible::value is true when T1 can // be implicitly converted to T2. TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); } // Tests that ImplicitlyConvertible::value is false when T1 // cannot be implicitly converted to T2. TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); } // Tests IsContainerTest. class NonContainer {}; TEST(IsContainerTestTest, WorksForNonContainer) { EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); } TEST(IsContainerTestTest, WorksForContainer) { EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); } // Tests ArrayEq(). TEST(ArrayEqTest, WorksForDegeneratedArrays) { EXPECT_TRUE(ArrayEq(5, 5L)); EXPECT_FALSE(ArrayEq('a', 0)); } TEST(ArrayEqTest, WorksForOneDimensionalArrays) { // Note that a and b are distinct but compatible types. const int a[] = { 0, 1 }; long b[] = { 0, 1 }; EXPECT_TRUE(ArrayEq(a, b)); EXPECT_TRUE(ArrayEq(a, 2, b)); b[0] = 2; EXPECT_FALSE(ArrayEq(a, b)); EXPECT_FALSE(ArrayEq(a, 1, b)); } TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { const char a[][3] = { "hi", "lo" }; const char b[][3] = { "hi", "lo" }; const char c[][3] = { "hi", "li" }; EXPECT_TRUE(ArrayEq(a, b)); EXPECT_TRUE(ArrayEq(a, 2, b)); EXPECT_FALSE(ArrayEq(a, c)); EXPECT_FALSE(ArrayEq(a, 2, c)); } // Tests ArrayAwareFind(). TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { const char a[] = "hello"; EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); } TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; const int b[2] = { 2, 3 }; EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); const int c[2] = { 6, 7 }; EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); } // Tests CopyArray(). TEST(CopyArrayTest, WorksForDegeneratedArrays) { int n = 0; CopyArray('a', &n); EXPECT_EQ('a', n); } TEST(CopyArrayTest, WorksForOneDimensionalArrays) { const char a[3] = "hi"; int b[3]; #ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. CopyArray(a, &b); EXPECT_TRUE(ArrayEq(a, b)); #endif int c[3]; CopyArray(a, 3, c); EXPECT_TRUE(ArrayEq(a, c)); } TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; int b[2][3]; #ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. CopyArray(a, &b); EXPECT_TRUE(ArrayEq(a, b)); #endif int c[2][3]; CopyArray(a, 2, c); EXPECT_TRUE(ArrayEq(a, c)); } // Tests NativeArray. TEST(NativeArrayTest, ConstructorFromArrayWorks) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, kReference); EXPECT_EQ(3U, na.size()); EXPECT_EQ(a, na.begin()); } TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { typedef int Array[2]; Array* a = new Array[1]; (*a)[0] = 0; (*a)[1] = 1; NativeArray na(*a, 2, kCopy); EXPECT_NE(*a, na.begin()); delete[] a; EXPECT_EQ(0, na.begin()[0]); EXPECT_EQ(1, na.begin()[1]); // We rely on the heap checker to verify that na deletes the copy of // array. } TEST(NativeArrayTest, TypeMembersAreCorrect) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::const_iterator>(); StaticAssertTypeEq::const_iterator>(); } TEST(NativeArrayTest, MethodsWork) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, kCopy); ASSERT_EQ(3U, na.size()); EXPECT_EQ(3, na.end() - na.begin()); NativeArray::const_iterator it = na.begin(); EXPECT_EQ(0, *it); ++it; EXPECT_EQ(1, *it); it++; EXPECT_EQ(2, *it); ++it; EXPECT_EQ(na.end(), it); EXPECT_TRUE(na == na); NativeArray na2(a, 3, kReference); EXPECT_TRUE(na == na2); const int b1[3] = { 0, 1, 1 }; const int b2[4] = { 0, 1, 2, 3 }; EXPECT_FALSE(na == NativeArray(b1, 3, kReference)); EXPECT_FALSE(na == NativeArray(b2, 4, kCopy)); } TEST(NativeArrayTest, WorksForTwoDimensionalArray) { const char a[2][3] = { "hi", "lo" }; NativeArray na(a, 2, kReference); ASSERT_EQ(2U, na.size()); EXPECT_EQ(a, na.begin()); } // Tests SkipPrefix(). TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { const char* const str = "hello"; const char* p = str; EXPECT_TRUE(SkipPrefix("", &p)); EXPECT_EQ(str, p); p = str; EXPECT_TRUE(SkipPrefix("hell", &p)); EXPECT_EQ(str + 4, p); } TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { const char* const str = "world"; const char* p = str; EXPECT_FALSE(SkipPrefix("W", &p)); EXPECT_EQ(str, p); p = str; EXPECT_FALSE(SkipPrefix("world!", &p)); EXPECT_EQ(str, p); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_outfile1_test_.cc000066400000000000000000000037331273231111400313770ustar00rootroot00000000000000// 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) // // gtest_xml_outfile1_test_ writes some xml via TestProperty used by // gtest_xml_outfiles_test.py #include "gtest/gtest.h" class PropertyOne : public testing::Test { protected: virtual void SetUp() { RecordProperty("SetUpProp", 1); } virtual void TearDown() { RecordProperty("TearDownProp", 1); } }; TEST_F(PropertyOne, TestSomeProperties) { RecordProperty("TestSomeProperty", 1); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_outfile2_test_.cc000066400000000000000000000037331273231111400314000ustar00rootroot00000000000000// 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) // // gtest_xml_outfile2_test_ writes some xml via TestProperty used by // gtest_xml_outfiles_test.py #include "gtest/gtest.h" class PropertyTwo : public testing::Test { protected: virtual void SetUp() { RecordProperty("SetUpProp", 2); } virtual void TearDown() { RecordProperty("TearDownProp", 2); } }; TEST_F(PropertyTwo, TestSomeProperties) { RecordProperty("TestSomeProperty", 2); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_outfiles_test.py000077500000000000000000000123341273231111400314050ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test for the gtest_xml_output module.""" __author__ = "keith.ray@gmail.com (Keith Ray)" import os from xml.dom import minidom, Node import gtest_test_utils import gtest_xml_test_utils GTEST_OUTPUT_SUBDIR = "xml_outfiles" GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_" GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_" EXPECTED_XML_1 = """ """ EXPECTED_XML_2 = """ """ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase): """Unit test for Google Test's XML output functionality.""" def setUp(self): # We want the trailing '/' that the last "" provides in os.path.join, for # telling Google Test to create an output directory instead of a single file # for xml output. self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(), GTEST_OUTPUT_SUBDIR, "") self.DeleteFilesAndDir() def tearDown(self): self.DeleteFilesAndDir() def DeleteFilesAndDir(self): try: os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml")) except os.error: pass try: os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml")) except os.error: pass try: os.rmdir(self.output_dir_) except os.error: pass def testOutfile1(self): self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1) def testOutfile2(self): self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2) def _TestOutFile(self, test_name, expected_xml): gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name) command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_] p = gtest_test_utils.Subprocess(command, working_dir=gtest_test_utils.GetTempDir()) self.assert_(p.exited) self.assertEquals(0, p.exit_code) # TODO(wan@google.com): libtool causes the built test binary to be # named lt-gtest_xml_outfiles_test_ instead of # gtest_xml_outfiles_test_. To account for this possibillity, we # allow both names in the following code. We should remove this # hack when Chandler Carruth's libtool replacement tool is ready. output_file_name1 = test_name + ".xml" output_file1 = os.path.join(self.output_dir_, output_file_name1) output_file_name2 = 'lt-' + output_file_name1 output_file2 = os.path.join(self.output_dir_, output_file_name2) self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2), output_file1) expected = minidom.parseString(expected_xml) if os.path.isfile(output_file1): actual = minidom.parse(output_file1) else: actual = minidom.parse(output_file2) self.NormalizeXml(actual.documentElement) self.AssertEquivalentNodes(expected.documentElement, actual.documentElement) expected.unlink() actual.unlink() if __name__ == "__main__": os.environ["GTEST_STACK_TRACE_DEPTH"] = "0" gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_output_unittest.py000077500000000000000000000343641273231111400320220ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test for the gtest_xml_output module""" __author__ = 'eefacm@gmail.com (Sean Mcafee)' import datetime import errno import os import re import sys from xml.dom import minidom, Node import gtest_test_utils import gtest_xml_test_utils GTEST_FILTER_FLAG = '--gtest_filter' GTEST_LIST_TESTS_FLAG = '--gtest_list_tests' GTEST_OUTPUT_FLAG = "--gtest_output" GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_" SUPPORTS_STACK_TRACES = False if SUPPORTS_STACK_TRACES: STACK_TRACE_TEMPLATE = '\nStack trace:\n*' else: STACK_TRACE_TEMPLATE = '' EXPECTED_NON_EMPTY_XML = """ ]]>%(stack)s]]> """ % {'stack': STACK_TRACE_TEMPLATE} EXPECTED_FILTERED_TEST_XML = """ """ EXPECTED_EMPTY_XML = """ """ GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess( [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): """ Unit test for Google Test's XML output functionality. """ # This test currently breaks on platforms that do not support typed and # type-parameterized tests, so we don't run it under them. if SUPPORTS_TYPED_TESTS: def testNonEmptyXmlOutput(self): """ Runs a test program that generates a non-empty XML output, and tests that the XML output is expected. """ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) def testEmptyXmlOutput(self): """Verifies XML output for a Google Test binary without actual tests. Runs a test program that generates an empty XML output, and tests that the XML output is expected. """ self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_EMPTY_XML, 0) def testTimestampValue(self): """Checks whether the timestamp attribute in the XML output is valid. Runs a test program that generates an empty XML output, and checks if the timestamp attribute in the testsuites tag is valid. """ actual = self._GetXmlOutput('gtest_no_test_unittest', [], 0) date_time_str = actual.documentElement.getAttributeNode('timestamp').value # datetime.strptime() is only available in Python 2.5+ so we have to # parse the expected datetime manually. match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str) self.assertTrue( re.match, 'XML datettime string %s has incorrect format' % date_time_str) date_time_from_xml = datetime.datetime( year=int(match.group(1)), month=int(match.group(2)), day=int(match.group(3)), hour=int(match.group(4)), minute=int(match.group(5)), second=int(match.group(6))) time_delta = abs(datetime.datetime.now() - date_time_from_xml) # timestamp value should be near the current local time self.assertTrue(time_delta < datetime.timedelta(seconds=600), 'time_delta is %s' % time_delta) actual.unlink() def testDefaultOutputFile(self): """ Confirms that Google Test produces an XML output file with the expected default name if no name is explicitly specified. """ output_file = os.path.join(gtest_test_utils.GetTempDir(), GTEST_DEFAULT_OUTPUT_FILE) gtest_prog_path = gtest_test_utils.GetTestExecutablePath( 'gtest_no_test_unittest') try: os.remove(output_file) except OSError, e: if e.errno != errno.ENOENT: raise p = gtest_test_utils.Subprocess( [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG], working_dir=gtest_test_utils.GetTempDir()) self.assert_(p.exited) self.assertEquals(0, p.exit_code) self.assert_(os.path.isfile(output_file)) def testSuppressedXmlOutput(self): """ Tests that no XML file is generated if the default XML listener is shut down before RUN_ALL_TESTS is invoked. """ xml_path = os.path.join(gtest_test_utils.GetTempDir(), GTEST_PROGRAM_NAME + 'out.xml') if os.path.isfile(xml_path): os.remove(xml_path) command = [GTEST_PROGRAM_PATH, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path), '--shut_down_xml'] p = gtest_test_utils.Subprocess(command) if p.terminated_by_signal: # p.signal is avalable only if p.terminated_by_signal is True. self.assertFalse( p.terminated_by_signal, '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal)) else: self.assert_(p.exited) self.assertEquals(1, p.exit_code, "'%s' exited with code %s, which doesn't match " 'the expected exit code %s.' % (command, p.exit_code, 1)) self.assert_(not os.path.isfile(xml_path)) def testFilteredTestXmlOutput(self): """Verifies XML output when a filter is applied. Runs a test program that executes only some tests and verifies that non-selected tests do not show up in the XML output. """ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED_TEST_XML, 0, extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG]) def _GetXmlOutput(self, gtest_prog_name, extra_args, expected_exit_code): """ Returns the xml output generated by running the program gtest_prog_name. Furthermore, the program's exit code must be expected_exit_code. """ xml_path = os.path.join(gtest_test_utils.GetTempDir(), gtest_prog_name + 'out.xml') gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name) command = ([gtest_prog_path, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path)] + extra_args) p = gtest_test_utils.Subprocess(command) if p.terminated_by_signal: self.assert_(False, '%s was killed by signal %d' % (gtest_prog_name, p.signal)) else: self.assert_(p.exited) self.assertEquals(expected_exit_code, p.exit_code, "'%s' exited with code %s, which doesn't match " 'the expected exit code %s.' % (command, p.exit_code, expected_exit_code)) actual = minidom.parse(xml_path) return actual def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code, extra_args=None): """ Asserts that the XML document generated by running the program gtest_prog_name matches expected_xml, a string containing another XML document. Furthermore, the program's exit code must be expected_exit_code. """ actual = self._GetXmlOutput(gtest_prog_name, extra_args or [], expected_exit_code) expected = minidom.parseString(expected_xml) self.NormalizeXml(actual.documentElement) self.AssertEquivalentNodes(expected.documentElement, actual.documentElement) expected.unlink() actual.unlink() if __name__ == '__main__': os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' gtest_test_utils.Main() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_output_unittest_.cc000066400000000000000000000137771273231111400321200ustar00rootroot00000000000000// 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: eefacm@gmail.com (Sean Mcafee) // Unit test for Google Test XML output. // // A user can specify XML output in a Google Test program to run via // either the GTEST_OUTPUT environment variable or the --gtest_output // flag. This is used for testing such functionality. // // This program will be invoked from a Python unit test. Don't run it // directly. #include "gtest/gtest.h" using ::testing::InitGoogleTest; using ::testing::TestEventListeners; using ::testing::TestWithParam; using ::testing::UnitTest; using ::testing::Test; using ::testing::Values; class SuccessfulTest : public Test { }; TEST_F(SuccessfulTest, Succeeds) { SUCCEED() << "This is a success."; ASSERT_EQ(1, 1); } class FailedTest : public Test { }; TEST_F(FailedTest, Fails) { ASSERT_EQ(1, 2); } class DisabledTest : public Test { }; TEST_F(DisabledTest, DISABLED_test_not_run) { FAIL() << "Unexpected failure: Disabled test should not be run"; } TEST(MixedResultTest, Succeeds) { EXPECT_EQ(1, 1); ASSERT_EQ(1, 1); } TEST(MixedResultTest, Fails) { EXPECT_EQ(1, 2); ASSERT_EQ(2, 3); } TEST(MixedResultTest, DISABLED_test) { FAIL() << "Unexpected failure: Disabled test should not be run"; } TEST(XmlQuotingTest, OutputsCData) { FAIL() << "XML output: " ""; } // Helps to test that invalid characters produced by test code do not make // it into the XML file. TEST(InvalidCharactersTest, InvalidCharactersInMessage) { FAIL() << "Invalid characters in brackets [\x1\x2]"; } class PropertyRecordingTest : public Test { public: static void SetUpTestCase() { RecordProperty("SetUpTestCase", "yes"); } static void TearDownTestCase() { RecordProperty("TearDownTestCase", "aye"); } }; TEST_F(PropertyRecordingTest, OneProperty) { RecordProperty("key_1", "1"); } TEST_F(PropertyRecordingTest, IntValuedProperty) { RecordProperty("key_int", 1); } TEST_F(PropertyRecordingTest, ThreeProperties) { RecordProperty("key_1", "1"); RecordProperty("key_2", "2"); RecordProperty("key_3", "3"); } TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue) { RecordProperty("key_1", "1"); RecordProperty("key_1", "2"); } TEST(NoFixtureTest, RecordProperty) { RecordProperty("key", "1"); } void ExternalUtilityThatCallsRecordProperty(const std::string& key, int value) { testing::Test::RecordProperty(key, value); } void ExternalUtilityThatCallsRecordProperty(const std::string& key, const std::string& value) { testing::Test::RecordProperty(key, value); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); } // Verifies that the test parameter value is output in the 'value_param' // XML attribute for value-parameterized tests. class ValueParamTest : public TestWithParam {}; TEST_P(ValueParamTest, HasValueParamAttribute) {} TEST_P(ValueParamTest, AnotherTestThatHasValueParamAttribute) {} INSTANTIATE_TEST_CASE_P(Single, ValueParamTest, Values(33, 42)); #if GTEST_HAS_TYPED_TEST // Verifies that the type parameter name is output in the 'type_param' // XML attribute for typed tests. template class TypedTest : public Test {}; typedef testing::Types TypedTestTypes; TYPED_TEST_CASE(TypedTest, TypedTestTypes); TYPED_TEST(TypedTest, HasTypeParamAttribute) {} #endif #if GTEST_HAS_TYPED_TEST_P // Verifies that the type parameter name is output in the 'type_param' // XML attribute for type-parameterized tests. template class TypeParameterizedTestCase : public Test {}; TYPED_TEST_CASE_P(TypeParameterizedTestCase); TYPED_TEST_P(TypeParameterizedTestCase, HasTypeParamAttribute) {} REGISTER_TYPED_TEST_CASE_P(TypeParameterizedTestCase, HasTypeParamAttribute); typedef testing::Types TypeParameterizedTestCaseTypes; INSTANTIATE_TYPED_TEST_CASE_P(Single, TypeParameterizedTestCase, TypeParameterizedTestCaseTypes); #endif int main(int argc, char** argv) { InitGoogleTest(&argc, argv); if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); delete listeners.Release(listeners.default_xml_generator()); } testing::Test::RecordProperty("ad_hoc_property", "42"); return RUN_ALL_TESTS(); } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/gtest_xml_test_utils.py000077500000000000000000000212541273231111400307140ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """Unit test utilities for gtest_xml_output""" __author__ = 'eefacm@gmail.com (Sean Mcafee)' import re from xml.dom import minidom, Node import gtest_test_utils GTEST_OUTPUT_FLAG = '--gtest_output' GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml' class GTestXMLTestCase(gtest_test_utils.TestCase): """ Base class for tests of Google Test's XML output functionality. """ def AssertEquivalentNodes(self, expected_node, actual_node): """ Asserts that actual_node (a DOM node object) is equivalent to expected_node (another DOM node object), in that either both of them are CDATA nodes and have the same value, or both are DOM elements and actual_node meets all of the following conditions: * It has the same tag name as expected_node. * It has the same set of attributes as expected_node, each with the same value as the corresponding attribute of expected_node. Exceptions are any attribute named "time", which needs only be convertible to a floating-point number and any attribute named "type_param" which only has to be non-empty. * It has an equivalent set of child nodes (including elements and CDATA sections) as expected_node. Note that we ignore the order of the children as they are not guaranteed to be in any particular order. """ if expected_node.nodeType == Node.CDATA_SECTION_NODE: self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType) self.assertEquals(expected_node.nodeValue, actual_node.nodeValue) return self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType) self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType) self.assertEquals(expected_node.tagName, actual_node.tagName) expected_attributes = expected_node.attributes actual_attributes = actual_node .attributes self.assertEquals( expected_attributes.length, actual_attributes.length, 'attribute numbers differ in element %s:\nExpected: %r\nActual: %r' % ( actual_node.tagName, expected_attributes.keys(), actual_attributes.keys())) for i in range(expected_attributes.length): expected_attr = expected_attributes.item(i) actual_attr = actual_attributes.get(expected_attr.name) self.assert_( actual_attr is not None, 'expected attribute %s not found in element %s' % (expected_attr.name, actual_node.tagName)) self.assertEquals( expected_attr.value, actual_attr.value, ' values of attribute %s in element %s differ: %s vs %s' % (expected_attr.name, actual_node.tagName, expected_attr.value, actual_attr.value)) expected_children = self._GetChildren(expected_node) actual_children = self._GetChildren(actual_node) self.assertEquals( len(expected_children), len(actual_children), 'number of child elements differ in element ' + actual_node.tagName) for child_id, child in expected_children.iteritems(): self.assert_(child_id in actual_children, '<%s> is not in <%s> (in element %s)' % (child_id, actual_children, actual_node.tagName)) self.AssertEquivalentNodes(child, actual_children[child_id]) identifying_attribute = { 'testsuites': 'name', 'testsuite': 'name', 'testcase': 'name', 'failure': 'message', } def _GetChildren(self, element): """ Fetches all of the child nodes of element, a DOM Element object. Returns them as the values of a dictionary keyed by the IDs of the children. For , and elements, the ID is the value of their "name" attribute; for elements, it is the value of the "message" attribute; CDATA sections and non-whitespace text nodes are concatenated into a single CDATA section with ID "detail". An exception is raised if any element other than the above four is encountered, if two child elements with the same identifying attributes are encountered, or if any other type of node is encountered. """ children = {} for child in element.childNodes: if child.nodeType == Node.ELEMENT_NODE: self.assert_(child.tagName in self.identifying_attribute, 'Encountered unknown element <%s>' % child.tagName) childID = child.getAttribute(self.identifying_attribute[child.tagName]) self.assert_(childID not in children) children[childID] = child elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: if 'detail' not in children: if (child.nodeType == Node.CDATA_SECTION_NODE or not child.nodeValue.isspace()): children['detail'] = child.ownerDocument.createCDATASection( child.nodeValue) else: children['detail'].nodeValue += child.nodeValue else: self.fail('Encountered unexpected node type %d' % child.nodeType) return children def NormalizeXml(self, element): """ Normalizes Google Test's XML output to eliminate references to transient information that may change from run to run. * The "time" attribute of , and elements is replaced with a single asterisk, if it contains only digit characters. * The "timestamp" attribute of elements is replaced with a single asterisk, if it contains a valid ISO8601 datetime value. * The "type_param" attribute of elements is replaced with a single asterisk (if it sn non-empty) as it is the type name returned by the compiler and is platform dependent. * The line info reported in the first line of the "message" attribute and CDATA section of elements is replaced with the file's basename and a single asterisk for the line number. * The directory names in file paths are removed. * The stack traces are removed. """ if element.tagName == 'testsuites': timestamp = element.getAttributeNode('timestamp') timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$', '*', timestamp.value) if element.tagName in ('testsuites', 'testsuite', 'testcase'): time = element.getAttributeNode('time') time.value = re.sub(r'^\d+(\.\d+)?$', '*', time.value) type_param = element.getAttributeNode('type_param') if type_param and type_param.value: type_param.value = '*' elif element.tagName == 'failure': source_line_pat = r'^.*[/\\](.*:)\d+\n' # Replaces the source line information with a normalized form. message = element.getAttributeNode('message') message.value = re.sub(source_line_pat, '\\1*\n', message.value) for child in element.childNodes: if child.nodeType == Node.CDATA_SECTION_NODE: # Replaces the source line information with a normalized form. cdata = re.sub(source_line_pat, '\\1*\n', child.nodeValue) # Removes the actual stack trace. child.nodeValue = re.sub(r'\nStack trace:\n(.|\n)*', '', cdata) for child in element.childNodes: if child.nodeType == Node.ELEMENT_NODE: self.NormalizeXml(child) mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/production.cc000066400000000000000000000033041273231111400265430ustar00rootroot00000000000000// 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) // // This is part of the unit test for include/gtest/gtest_prod.h. #include "production.h" PrivateCode::PrivateCode() : x_(0) {} mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/test/production.h000066400000000000000000000041741273231111400264130ustar00rootroot00000000000000// 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) // // This is part of the unit test for include/gtest/gtest_prod.h. #ifndef GTEST_TEST_PRODUCTION_H_ #define GTEST_TEST_PRODUCTION_H_ #include "gtest/gtest_prod.h" class PrivateCode { public: // Declares a friend test that does not use a fixture. FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers); // Declares a friend test that uses a fixture. FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers); PrivateCode(); int x() const { return x_; } private: void set_x(int an_x) { x_ = an_x; } int x_; }; #endif // GTEST_TEST_PRODUCTION_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/000077500000000000000000000000001273231111400241715ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/000077500000000000000000000000001273231111400253765ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/DebugProject.xcconfig000066400000000000000000000017271273231111400315040ustar00rootroot00000000000000// // DebugProject.xcconfig // // These are Debug Configuration project settings for the gtest framework and // examples. It is set in the "Based On:" dropdown in the "Project" info // dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // #include "General.xcconfig" // No optimization GCC_OPTIMIZATION_LEVEL = 0 // Deployment postprocessing is what triggers Xcode to strip, turn it off DEPLOYMENT_POSTPROCESSING = NO // Dead code stripping off DEAD_CODE_STRIPPING = NO // Debug symbols should be on obviously GCC_GENERATE_DEBUGGING_SYMBOLS = YES // Define the DEBUG macro in all debug builds OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1 // These are turned off to avoid STL incompatibilities with client code // // Turns on special C++ STL checks to "encourage" good STL use // GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/FrameworkTarget.xcconfig000066400000000000000000000010471273231111400322260ustar00rootroot00000000000000// // FrameworkTarget.xcconfig // // These are Framework target settings for the gtest framework and examples. It // is set in the "Based On:" dropdown in the "Target" info dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Dynamic libs need to be position independent GCC_DYNAMIC_NO_PIC = NO // Dynamic libs should not have their external symbols stripped. STRIP_STYLE = non-global // Let the user install by specifying the $DSTROOT with xcodebuild SKIP_INSTALL = NO mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/General.xcconfig000066400000000000000000000022571273231111400305030ustar00rootroot00000000000000// // General.xcconfig // // These are General configuration settings for the gtest framework and // examples. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Build for PPC and Intel, 32- and 64-bit ARCHS = i386 x86_64 ppc ppc64 // Zerolink prevents link warnings so turn it off ZERO_LINK = NO // Prebinding considered unhelpful in 10.3 and later PREBINDING = NO // Strictest warning policy WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow // Work around Xcode bugs by using external strip. See: // http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html SEPARATE_STRIP = YES // Force C99 dialect GCC_C_LANGUAGE_STANDARD = c99 // not sure why apple defaults this on, but it's pretty risky ALWAYS_SEARCH_USER_PATHS = NO // Turn on position dependent code for most cases (overridden where appropriate) GCC_DYNAMIC_NO_PIC = YES // Default SDK and minimum OS version is 10.4 SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk MACOSX_DEPLOYMENT_TARGET = 10.4 GCC_VERSION = 4.0 // VERSIONING BUILD SETTINGS (used in Info.plist) GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc. mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/ReleaseProject.xcconfig000066400000000000000000000017411273231111400320320ustar00rootroot00000000000000// // ReleaseProject.xcconfig // // These are Release Configuration project settings for the gtest framework // and examples. It is set in the "Based On:" dropdown in the "Project" info // dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // #include "General.xcconfig" // subconfig/Release.xcconfig // Optimize for space and size (Apple recommendation) GCC_OPTIMIZATION_LEVEL = s // Deploment postprocessing is what triggers Xcode to strip DEPLOYMENT_POSTPROCESSING = YES // No symbols GCC_GENERATE_DEBUGGING_SYMBOLS = NO // Dead code strip does not affect ObjC code but can help for C DEAD_CODE_STRIPPING = YES // NDEBUG is used by things like assert.h, so define it for general compat. // ASSERT going away in release tends to create unused vars. OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable // When we strip we want to strip all symbols in release, but save externals. STRIP_STYLE = all mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/StaticLibraryTarget.xcconfig000066400000000000000000000011131273231111400330370ustar00rootroot00000000000000// // StaticLibraryTarget.xcconfig // // These are static library target settings for libgtest.a. It // is set in the "Based On:" dropdown in the "Target" info dialog. // This file is based on the Xcode Configuration files in: // http://code.google.com/p/google-toolbox-for-mac/ // // Static libs can be included in bundles so make them position independent GCC_DYNAMIC_NO_PIC = NO // Static libs should not have their internal globals or external symbols // stripped. STRIP_STYLE = debugging // Let the user install by specifying the $DSTROOT with xcodebuild SKIP_INSTALL = NO mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Config/TestTarget.xcconfig000066400000000000000000000003561273231111400312120ustar00rootroot00000000000000// // TestTarget.xcconfig // // These are Test target settings for the gtest framework and examples. It // is set in the "Based On:" dropdown in the "Target" info dialog. PRODUCT_NAME = $(TARGET_NAME) HEADER_SEARCH_PATHS = ../include mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Resources/000077500000000000000000000000001273231111400261435ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Resources/Info.plist000066400000000000000000000017621273231111400301210ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.${PRODUCT_NAME} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType FMWK CFBundleSignature ???? CFBundleVersion GTEST_VERSIONINFO_LONG CFBundleShortVersionString GTEST_VERSIONINFO_SHORT CFBundleGetInfoString ${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT} NSHumanReadableCopyright ${GTEST_VERSIONINFO_ABOUT} CSResourcesFileMapped mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/000077500000000000000000000000001273231111400255755ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/000077500000000000000000000000001273231111400306745ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/Info.plist000066400000000000000000000015161273231111400326470ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.gtest.${PRODUCT_NAME:identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 CSResourcesFileMapped 000077500000000000000000000000001273231111400357125ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/WidgetFramework.xcodeprojproject.pbxproj000066400000000000000000000372741273231111400410030ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXAggregateTarget section */ 4024D162113D7D2400C7059E /* Test */ = { isa = PBXAggregateTarget; buildConfigurationList = 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */; buildPhases = ( 4024D161113D7D2400C7059E /* ShellScript */, ); dependencies = ( 4024D166113D7D3100C7059E /* PBXTargetDependency */, ); name = Test; productName = TestAndBuild; }; 4024D1E9113D83FF00C7059E /* TestAndBuild */ = { isa = PBXAggregateTarget; buildConfigurationList = 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */; buildPhases = ( ); dependencies = ( 4024D1ED113D840900C7059E /* PBXTargetDependency */, 4024D1EF113D840D00C7059E /* PBXTargetDependency */, ); name = TestAndBuild; productName = TestAndBuild; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1230E5AEE3500C7F239 /* widget.cc */; }; 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7EB1240E5AEE3500C7F239 /* widget.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */; }; 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; }; 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D185113D7D5500C7059E /* libgtest.a */; }; 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D183113D7D5500C7059E /* libgtest_main.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = gTestExample; }; 4024D165113D7D3100C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 3B07BDE90E3F3F9E00647869; remoteInfo = WidgetFrameworkTest; }; 4024D1EC113D840900C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = WidgetFramework; }; 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 4024D162113D7D2400C7059E; remoteInfo = Test; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WidgetFrameworkTest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B7EB1230E5AEE3500C7F239 /* widget.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget.cc; sourceTree = ""; }; 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = ""; }; 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = ""; }; 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = ""; }; 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = ""; }; 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D07F2C80486CC7A007CD1D0 /* Widget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Widget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3B07BDE80E3F3F9E00647869 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */, 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */, 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 034768DDFF38A45A11DB9C8B /* Products */ = { isa = PBXGroup; children = ( 8D07F2C80486CC7A007CD1D0 /* Widget.framework */, 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */, ); name = Products; sourceTree = ""; }; 0867D691FE84028FC02AAC07 /* gTestExample */ = { isa = PBXGroup; children = ( 4024D1E1113D836C00C7059E /* Scripts */, 08FB77ACFE841707C02AAC07 /* Source */, 089C1665FE841158C02AAC07 /* Resources */, 3B07BE350E4094E400647869 /* Test */, 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gTestExample; sourceTree = ""; }; 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { isa = PBXGroup; children = ( 4024D183113D7D5500C7059E /* libgtest_main.a */, 4024D185113D7D5500C7059E /* libgtest.a */, ); name = "External Frameworks and Libraries"; sourceTree = ""; }; 089C1665FE841158C02AAC07 /* Resources */ = { isa = PBXGroup; children = ( 8D07F2C70486CC7A007CD1D0 /* Info.plist */, ); name = Resources; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 3B7EB1230E5AEE3500C7F239 /* widget.cc */, 3B7EB1240E5AEE3500C7F239 /* widget.h */, ); name = Source; sourceTree = ""; }; 3B07BE350E4094E400647869 /* Test */ = { isa = PBXGroup; children = ( 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */, ); name = Test; sourceTree = ""; }; 4024D1E1113D836C00C7059E /* Scripts */ = { isa = PBXGroup; children = ( 4024D1E2113D838200C7059E /* runtests.sh */, ); name = Scripts; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */ = { isa = PBXNativeTarget; buildConfigurationList = 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */; buildPhases = ( 3B07BDE70E3F3F9E00647869 /* Sources */, 3B07BDE80E3F3F9E00647869 /* Frameworks */, ); buildRules = ( ); dependencies = ( 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */, ); name = WidgetFrameworkTest; productName = gTestExampleTest; productReference = 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */; productType = "com.apple.product-type.tool"; }; 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */ = { isa = PBXNativeTarget; buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */; buildPhases = ( 8D07F2C10486CC7A007CD1D0 /* Sources */, 8D07F2C30486CC7A007CD1D0 /* Frameworks */, 8D07F2BD0486CC7A007CD1D0 /* Headers */, 8D07F2BF0486CC7A007CD1D0 /* Resources */, 8D07F2C50486CC7A007CD1D0 /* Rez */, ); buildRules = ( ); dependencies = ( ); name = WidgetFramework; productInstallPath = "$(HOME)/Library/Frameworks"; productName = gTestExample; productReference = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */; compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 0867D691FE84028FC02AAC07 /* gTestExample */; productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */, 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */, 4024D162113D7D2400C7059E /* Test */, 4024D1E9113D83FF00C7059E /* TestAndBuild */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXRezBuildPhase section */ 8D07F2C50486CC7A007CD1D0 /* Rez */ = { isa = PBXRezBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXRezBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4024D161113D7D2400C7059E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/bash $SRCROOT/runtests.sh $BUILT_PRODUCTS_DIR/WidgetFrameworkTest\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3B07BDE70E3F3F9E00647869 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C10486CC7A007CD1D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; targetProxy = 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */; }; 4024D166113D7D3100C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */; targetProxy = 4024D165113D7D3100C7059E /* PBXContainerItemProxy */; }; 4024D1ED113D840900C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */; targetProxy = 4024D1EC113D840900C7059E /* PBXContainerItemProxy */; }; 4024D1EF113D840D00C7059E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4024D162113D7D2400C7059E /* Test */; targetProxy = 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 3B07BDEC0E3F3F9F00647869 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = WidgetFrameworkTest; }; name = Debug; }; 3B07BDED0E3F3F9F00647869 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = WidgetFrameworkTest; }; name = Release; }; 4024D163113D7D2400C7059E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Debug; }; 4024D164113D7D2400C7059E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Release; }; 4024D1EA113D83FF00C7059E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Debug; }; 4024D1EB113D83FF00C7059E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = TestAndBuild; }; name = Release; }; 4FADC24308B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "@loader_path/../Frameworks"; PRODUCT_NAME = Widget; }; name = Debug; }; 4FADC24408B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "@loader_path/../Frameworks"; PRODUCT_NAME = Widget; }; name = Release; }; 4FADC24708B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = 4.0; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Debug; }; 4FADC24808B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = 4.0; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */ = { isa = XCConfigurationList; buildConfigurations = ( 3B07BDEC0E3F3F9F00647869 /* Debug */, 3B07BDED0E3F3F9F00647869 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */ = { isa = XCConfigurationList; buildConfigurations = ( 4024D163113D7D2400C7059E /* Debug */, 4024D164113D7D2400C7059E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */ = { isa = XCConfigurationList; buildConfigurations = ( 4024D1EA113D83FF00C7059E /* Debug */, 4024D1EB113D83FF00C7059E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24308B4156D00ABE55E /* Debug */, 4FADC24408B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24708B4156D00ABE55E /* Debug */, 4FADC24808B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/runtests.sh000066400000000000000000000044621273231111400331250ustar00rootroot00000000000000#!/bin/bash # # 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. # Executes the samples and tests for the Google Test Framework. # Help the dynamic linker find the path to the libraries. export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR # Create some executables. test_executables=$@ # Now execute each one in turn keeping track of how many succeeded and failed. succeeded=0 failed=0 failed_list=() for test in ${test_executables[*]}; do "$test" result=$? if [ $result -eq 0 ]; then succeeded=$(( $succeeded + 1 )) else failed=$(( failed + 1 )) failed_list="$failed_list $test" fi done # Report the successes and failures to the console. echo "Tests complete with $succeeded successes and $failed failures." if [ $failed -ne 0 ]; then echo "The following tests failed:" echo $failed_list fi exit $failed mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/widget.cc000066400000000000000000000044031273231111400324670ustar00rootroot00000000000000// 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: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget.cc // // Widget is a very simple class used for demonstrating the use of gtest #include "widget.h" Widget::Widget(int number, const std::string& name) : number_(number), name_(name) {} Widget::~Widget() {} float Widget::GetFloatValue() const { return number_; } int Widget::GetIntValue() const { return static_cast(number_); } std::string Widget::GetStringValue() const { return name_; } void Widget::GetCharPtrValue(char* buffer, size_t max_size) const { // Copy the char* representation of name_ into buffer, up to max_size. strncpy(buffer, name_.c_str(), max_size-1); buffer[max_size-1] = '\0'; return; } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample/widget.h000066400000000000000000000043361273231111400323360ustar00rootroot00000000000000// 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: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget.h // // Widget is a very simple class used for demonstrating the use of gtest. It // simply stores two values a string and an integer, which are returned via // public accessors in multiple forms. #import class Widget { public: Widget(int number, const std::string& name); ~Widget(); // Public accessors to number data float GetFloatValue() const; int GetIntValue() const; // Public accessors to the string data std::string GetStringValue() const; void GetCharPtrValue(char* buffer, size_t max_size) const; private: // Data members float number_; std::string name_; }; widget_test.cc000066400000000000000000000051551273231111400334540ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Samples/FrameworkSample// 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: preston.a.jackson@gmail.com (Preston Jackson) // // Google Test - FrameworkSample // widget_test.cc // // This is a simple test file for the Widget class in the Widget.framework #include #include "gtest/gtest.h" #include // This test verifies that the constructor sets the internal state of the // Widget class correctly. TEST(WidgetInitializerTest, TestConstructor) { Widget widget(1.0f, "name"); EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue()); EXPECT_EQ(std::string("name"), widget.GetStringValue()); } // This test verifies the conversion of the float and string values to int and // char*, respectively. TEST(WidgetInitializerTest, TestConversion) { Widget widget(1.0f, "name"); EXPECT_EQ(1, widget.GetIntValue()); size_t max_size = 128; char buffer[max_size]; widget.GetCharPtrValue(buffer, max_size); EXPECT_STREQ("name", buffer); } // Use the Google Test main that is linked into the framework. It does something // like this: // int main(int argc, char** argv) { // testing::InitGoogleTest(&argc, argv); // return RUN_ALL_TESTS(); // } mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Scripts/000077500000000000000000000000001273231111400256205ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Scripts/runtests.sh000066400000000000000000000050331273231111400300440ustar00rootroot00000000000000#!/bin/bash # # 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. # Executes the samples and tests for the Google Test Framework. # Help the dynamic linker find the path to the libraries. export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR # Create some executables. test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework" "$BUILT_PRODUCTS_DIR/gtest_unittest" "$BUILT_PRODUCTS_DIR/sample1_unittest-framework" "$BUILT_PRODUCTS_DIR/sample1_unittest-static") # Now execute each one in turn keeping track of how many succeeded and failed. succeeded=0 failed=0 failed_list=() for test in ${test_executables[*]}; do "$test" result=$? if [ $result -eq 0 ]; then succeeded=$(( $succeeded + 1 )) else failed=$(( failed + 1 )) failed_list="$failed_list $test" fi done # Report the successes and failures to the console. echo "Tests complete with $succeeded successes and $failed failures." if [ $failed -ne 0 ]; then echo "The following tests failed:" echo $failed_list fi exit $failed mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/Scripts/versiongenerate.py000077500000000000000000000106701273231111400314010ustar00rootroot00000000000000#!/usr/bin/env python # # 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. """A script to prepare version informtion for use the gtest Info.plist file. This script extracts the version information from the configure.ac file and uses it to generate a header file containing the same information. The #defines in this header file will be included in during the generation of the Info.plist of the framework, giving the correct value to the version shown in the Finder. This script makes the following assumptions (these are faults of the script, not problems with the Autoconf): 1. The AC_INIT macro will be contained within the first 1024 characters of configure.ac 2. The version string will be 3 integers separated by periods and will be surrounded by squre brackets, "[" and "]" (e.g. [1.0.1]). The first segment represents the major version, the second represents the minor version and the third represents the fix version. 3. No ")" character exists between the opening "(" and closing ")" of AC_INIT, including in comments and character strings. """ import sys import re # Read the command line argument (the output directory for Version.h) if (len(sys.argv) < 3): print "Usage: versiongenerate.py input_dir output_dir" sys.exit(1) else: input_dir = sys.argv[1] output_dir = sys.argv[2] # Read the first 1024 characters of the configure.ac file config_file = open("%s/configure.ac" % input_dir, 'r') buffer_size = 1024 opening_string = config_file.read(buffer_size) config_file.close() # Extract the version string from the AC_INIT macro # The following init_expression means: # Extract three integers separated by periods and surrounded by squre # brackets(e.g. "[1.0.1]") between "AC_INIT(" and ")". Do not be greedy # (*? is the non-greedy flag) since that would pull in everything between # the first "(" and the last ")" in the file. version_expression = re.compile(r"AC_INIT\(.*?\[(\d+)\.(\d+)\.(\d+)\].*?\)", re.DOTALL) version_values = version_expression.search(opening_string) major_version = version_values.group(1) minor_version = version_values.group(2) fix_version = version_values.group(3) # Write the version information to a header file to be included in the # Info.plist file. file_data = """// // DO NOT MODIFY THIS FILE (but you can delete it) // // This file is autogenerated by the versiongenerate.py script. This script // is executed in a "Run Script" build phase when creating gtest.framework. This // header file is not used during compilation of C-source. Rather, it simply // defines some version strings for substitution in the Info.plist. Because of // this, we are not not restricted to C-syntax nor are we using include guards. // #define GTEST_VERSIONINFO_SHORT %s.%s #define GTEST_VERSIONINFO_LONG %s.%s.%s """ % (major_version, minor_version, major_version, minor_version, fix_version) version_file = open("%s/Version.h" % output_dir, 'w') version_file.write(file_data) version_file.close() mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/gtest.xcodeproj/000077500000000000000000000000001273231111400273135ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/gtest-1.7.0/xcode/gtest.xcodeproj/project.pbxproj000066400000000000000000001434341273231111400324000ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXAggregateTarget section */ 3B238F5F0E828B5400846E11 /* Check */ = { isa = PBXAggregateTarget; buildConfigurationList = 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */; buildPhases = ( 3B238F5E0E828B5400846E11 /* ShellScript */, ); dependencies = ( 40899F9D0FFA740F000B29AE /* PBXTargetDependency */, 40C849F7101A43440083642A /* PBXTargetDependency */, 4089A0980FFAD34A000B29AE /* PBXTargetDependency */, 40C849F9101A43490083642A /* PBXTargetDependency */, ); name = Check; productName = Check; }; 40C44ADC0E3798F4008FCC51 /* Version Info */ = { isa = PBXAggregateTarget; buildConfigurationList = 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */; buildPhases = ( 40C44ADB0E3798F4008FCC51 /* Generate Version.h */, ); comments = "The generation of Version.h must be performed in its own target. Since the Info.plist is preprocessed before any of the other build phases in gtest, the Version.h file would not be ready if included as a build phase of that target."; dependencies = ( ); name = "Version Info"; productName = Version.h; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */; }; 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843B0E2F799B00CF7658 /* gtest.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DE0E2F799B00CF7658 /* gtest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883E00E2F799B00CF7658 /* gtest_prod.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884500E2F799B00CF7658 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README */; }; 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */; }; 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E30E2F799B00CF7658 /* gtest-filepath.h */; }; 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E40E2F799B00CF7658 /* gtest-internal.h */; }; 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E50E2F799B00CF7658 /* gtest-port.h */; }; 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E60E2F799B00CF7658 /* gtest-string.h */; }; 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */ = {isa = PBXBuildFile; fileRef = 404884A90E2F7CD900CF7658 /* CHANGES */; }; 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */; }; 404884AE0E2F7CD900CF7658 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* LICENSE */; }; 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 40899F4D0FFA7271000B29AE /* gtest-tuple.h */; }; 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; 40C848FF101A21150083642A /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; }; 40C84915101A21DF0083642A /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4048840D0E2F799B00CF7658 /* gtest_main.cc */; }; 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84978101A36540083642A /* libgtest_main.a in Resources */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C84980101A36850083642A /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; }; 40C84982101A36850083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; 40C84983101A36850083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C8498F101A36A60083642A /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; }; 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; }; 40C84992101A36A60083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; }; 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; }; 40C849A2101A37050083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; 40C849A4101A37150083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; }; 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 4539C9330EC280AE00A70F4C /* gtest-param-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */; }; 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */; }; 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9370EC280E200A70F4C /* gtest-param-util.h */; }; 4567C8181264FF71007740BE /* gtest-printers.h in Headers */ = {isa = PBXBuildFile; fileRef = 4567C8171264FF71007740BE /* gtest-printers.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40899F420FFA7184000B29AE; remoteInfo = gtest_unittest; }; 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 4089A0120FFACEFC000B29AE; remoteInfo = sample1_unittest; }; 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C44ADC0E3798F4008FCC51; remoteInfo = Version.h; }; 40C8497C101A36850083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C8497E101A36850083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8498B101A36A60083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C848F9101A209C0083642A; remoteInfo = "gtest-static"; }; 40C8498D101A36A60083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8499B101A36DC0083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8490A101A217E0083642A; remoteInfo = "gtest_main-static"; }; 40C8499D101A36E50083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = "gtest-framework"; }; 40C8499F101A36F10083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; remoteInfo = "gtest-framework"; }; 40C849F6101A43440083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C8497A101A36850083642A; remoteInfo = "gtest_unittest-static"; }; 40C849F8101A43490083642A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = 40C84989101A36A60083642A; remoteInfo = "sample1_unittest-static"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = Headers/internal; dstSubfolderSpec = 6; files = ( 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */, 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */, 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */, 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */, 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */, 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */, 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */, 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */, 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */, 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */, ); name = "Copy Headers Internal"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 224A12A10E9EADA700BD17FD /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = ""; }; 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = ""; }; 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = ""; }; 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = ""; }; 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = ""; }; 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = ""; }; 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = ""; }; 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = ""; }; 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = ""; }; 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = ""; }; 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = ""; }; 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = ""; }; 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = ""; }; 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = ""; }; 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = ""; }; 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = ""; }; 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = ""; }; 404883F60E2F799B00CF7658 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = ../README; sourceTree = SOURCE_ROOT; }; 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = ""; }; 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; }; 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; }; 404884AB0E2F7CD900CF7658 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = SOURCE_ROOT; }; 40899F430FFA7184000B29AE /* gtest_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gtest_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 40899F4D0FFA7271000B29AE /* gtest-tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-tuple.h"; sourceTree = ""; }; 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = ""; }; 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 4089A02C0FFACF7F000B29AE /* sample1.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1.cc; sourceTree = ""; }; 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = ""; }; 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = ""; }; 40C848FA101A209C0083642A /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40C8490B101A217E0083642A /* libgtest_main.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest_main.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40C84987101A36850083642A /* gtest_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gtest_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; 40C84997101A36A60083642A /* sample1_unittest-static */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-static"; sourceTree = BUILT_PRODUCTS_DIR; }; 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugProject.xcconfig; sourceTree = ""; }; 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = ""; }; 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = ""; }; 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4539C8FF0EC27F6400A70F4C /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4539C9330EC280AE00A70F4C /* gtest-param-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-test.h"; sourceTree = ""; }; 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = ""; }; 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = ""; }; 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = ""; }; 4567C8171264FF71007740BE /* gtest-printers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-printers.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 40899F410FFA7184000B29AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C849A4101A37150083642A /* gtest.framework in Frameworks */, 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 4089A0110FFACEFC000B29AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C849A2101A37050083642A /* gtest.framework in Frameworks */, 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84981101A36850083642A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C84982101A36850083642A /* libgtest.a in Frameworks */, 40C84983101A36850083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84991101A36A60083642A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 40C84992101A36A60083642A /* libgtest.a in Frameworks */, 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 034768DDFF38A45A11DB9C8B /* Products */ = { isa = PBXGroup; children = ( 4539C8FF0EC27F6400A70F4C /* gtest.framework */, 40C848FA101A209C0083642A /* libgtest.a */, 40C8490B101A217E0083642A /* libgtest_main.a */, 40899F430FFA7184000B29AE /* gtest_unittest-framework */, 40C84987101A36850083642A /* gtest_unittest */, 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */, 40C84997101A36A60083642A /* sample1_unittest-static */, ); name = Products; sourceTree = ""; }; 0867D691FE84028FC02AAC07 /* gtest */ = { isa = PBXGroup; children = ( 40D4CDF00E30E07400294801 /* Config */, 08FB77ACFE841707C02AAC07 /* Source */, 40D4CF4E0E30F5E200294801 /* Resources */, 403EE37B0E377822004BD1E2 /* Scripts */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gtest; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 404884A90E2F7CD900CF7658 /* CHANGES */, 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */, 404884AB0E2F7CD900CF7658 /* LICENSE */, 404883F60E2F799B00CF7658 /* README */, 404883D90E2F799B00CF7658 /* include */, 4089A02F0FFACF84000B29AE /* samples */, 404884070E2F799B00CF7658 /* src */, 3B238BF00E7FE13B00846E11 /* test */, ); name = Source; sourceTree = ""; }; 3B238BF00E7FE13B00846E11 /* test */ = { isa = PBXGroup; children = ( 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */, ); name = test; path = ../test; sourceTree = SOURCE_ROOT; }; 403EE37B0E377822004BD1E2 /* Scripts */ = { isa = PBXGroup; children = ( 403EE37C0E377822004BD1E2 /* versiongenerate.py */, 3B87D2100E96B92E000D1852 /* runtests.sh */, ); path = Scripts; sourceTree = ""; }; 404883D90E2F799B00CF7658 /* include */ = { isa = PBXGroup; children = ( 404883DA0E2F799B00CF7658 /* gtest */, ); name = include; path = ../include; sourceTree = SOURCE_ROOT; }; 404883DA0E2F799B00CF7658 /* gtest */ = { isa = PBXGroup; children = ( 404883E10E2F799B00CF7658 /* internal */, 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */, 404883DB0E2F799B00CF7658 /* gtest-death-test.h */, 404883DC0E2F799B00CF7658 /* gtest-message.h */, 4539C9330EC280AE00A70F4C /* gtest-param-test.h */, 4567C8171264FF71007740BE /* gtest-printers.h */, 404883DD0E2F799B00CF7658 /* gtest-spi.h */, 404883DE0E2F799B00CF7658 /* gtest.h */, 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */, 404883E00E2F799B00CF7658 /* gtest_prod.h */, 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */, ); path = gtest; sourceTree = ""; }; 404883E10E2F799B00CF7658 /* internal */ = { isa = PBXGroup; children = ( 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */, 404883E30E2F799B00CF7658 /* gtest-filepath.h */, 404883E40E2F799B00CF7658 /* gtest-internal.h */, 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */, 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */, 4539C9370EC280E200A70F4C /* gtest-param-util.h */, 404883E50E2F799B00CF7658 /* gtest-port.h */, 404883E60E2F799B00CF7658 /* gtest-string.h */, 40899F4D0FFA7271000B29AE /* gtest-tuple.h */, 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */, ); path = internal; sourceTree = ""; }; 404884070E2F799B00CF7658 /* src */ = { isa = PBXGroup; children = ( 224A12A10E9EADA700BD17FD /* gtest-all.cc */, 4048840D0E2F799B00CF7658 /* gtest_main.cc */, ); name = src; path = ../src; sourceTree = SOURCE_ROOT; }; 4089A02F0FFACF84000B29AE /* samples */ = { isa = PBXGroup; children = ( 4089A02C0FFACF7F000B29AE /* sample1.cc */, 4089A02D0FFACF7F000B29AE /* sample1.h */, 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */, ); name = samples; path = ../samples; sourceTree = SOURCE_ROOT; }; 40D4CDF00E30E07400294801 /* Config */ = { isa = PBXGroup; children = ( 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */, 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */, 40D4CDF30E30E07400294801 /* General.xcconfig */, 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */, 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */, ); path = Config; sourceTree = ""; }; 40D4CF4E0E30F5E200294801 /* Resources */ = { isa = PBXGroup; children = ( 40D4CF510E30F5E200294801 /* Info.plist */, ); path = Resources; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */, 404884390E2F799B00CF7658 /* gtest-message.h in Headers */, 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */, 4567C8181264FF71007740BE /* gtest-printers.h in Headers */, 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */, 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */, 4048843B0E2F799B00CF7658 /* gtest.h in Headers */, 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */, 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */, 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 40899F420FFA7184000B29AE /* gtest_unittest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */; buildPhases = ( 40899F400FFA7184000B29AE /* Sources */, 40899F410FFA7184000B29AE /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C849A0101A36F10083642A /* PBXTargetDependency */, ); name = "gtest_unittest-framework"; productName = gtest_unittest; productReference = 40899F430FFA7184000B29AE /* gtest_unittest-framework */; productType = "com.apple.product-type.tool"; }; 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */; buildPhases = ( 4089A0100FFACEFC000B29AE /* Sources */, 4089A0110FFACEFC000B29AE /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8499E101A36E50083642A /* PBXTargetDependency */, ); name = "sample1_unittest-framework"; productName = sample1_unittest; productReference = 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */; productType = "com.apple.product-type.tool"; }; 40C848F9101A209C0083642A /* gtest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */; buildPhases = ( 40C848F7101A209C0083642A /* Sources */, ); buildRules = ( ); dependencies = ( ); name = "gtest-static"; productName = "gtest-static"; productReference = 40C848FA101A209C0083642A /* libgtest.a */; productType = "com.apple.product-type.library.static"; }; 40C8490A101A217E0083642A /* gtest_main-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */; buildPhases = ( 40C84908101A217E0083642A /* Sources */, ); buildRules = ( ); dependencies = ( ); name = "gtest_main-static"; productName = "gtest_main-static"; productReference = 40C8490B101A217E0083642A /* libgtest_main.a */; productType = "com.apple.product-type.library.static"; }; 40C8497A101A36850083642A /* gtest_unittest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */; buildPhases = ( 40C8497F101A36850083642A /* Sources */, 40C84981101A36850083642A /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8497B101A36850083642A /* PBXTargetDependency */, 40C8497D101A36850083642A /* PBXTargetDependency */, ); name = "gtest_unittest-static"; productName = gtest_unittest; productReference = 40C84987101A36850083642A /* gtest_unittest */; productType = "com.apple.product-type.tool"; }; 40C84989101A36A60083642A /* sample1_unittest-static */ = { isa = PBXNativeTarget; buildConfigurationList = 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */; buildPhases = ( 40C8498E101A36A60083642A /* Sources */, 40C84991101A36A60083642A /* Frameworks */, ); buildRules = ( ); dependencies = ( 40C8498A101A36A60083642A /* PBXTargetDependency */, 40C8498C101A36A60083642A /* PBXTargetDependency */, ); name = "sample1_unittest-static"; productName = sample1_unittest; productReference = 40C84997101A36A60083642A /* sample1_unittest-static */; productType = "com.apple.product-type.tool"; }; 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */ = { isa = PBXNativeTarget; buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */; buildPhases = ( 8D07F2C10486CC7A007CD1D0 /* Sources */, 8D07F2BD0486CC7A007CD1D0 /* Headers */, 404884A50E2F7C0400CF7658 /* Copy Headers Internal */, 8D07F2BF0486CC7A007CD1D0 /* Resources */, ); buildRules = ( ); dependencies = ( 40C44AE60E379922008FCC51 /* PBXTargetDependency */, 408BEC101046CFE900DEF522 /* PBXTargetDependency */, 40C8499C101A36DC0083642A /* PBXTargetDependency */, ); name = "gtest-framework"; productInstallPath = "$(HOME)/Library/Frameworks"; productName = gtest; productReference = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0460; }; buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, en, ); mainGroup = 0867D691FE84028FC02AAC07 /* gtest */; productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */, 40C848F9101A209C0083642A /* gtest-static */, 40C8490A101A217E0083642A /* gtest_main-static */, 40899F420FFA7184000B29AE /* gtest_unittest-framework */, 40C8497A101A36850083642A /* gtest_unittest-static */, 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */, 40C84989101A36A60083642A /* sample1_unittest-static */, 3B238F5F0E828B5400846E11 /* Check */, 40C44ADC0E3798F4008FCC51 /* Version Info */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 404884500E2F799B00CF7658 /* README in Resources */, 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */, 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */, 404884AE0E2F7CD900CF7658 /* LICENSE in Resources */, 40C84978101A36540083642A /* libgtest_main.a in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B238F5E0E828B5400846E11 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/bin/bash Scripts/runtests.sh"; }; 40C44ADB0E3798F4008FCC51 /* Generate Version.h */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/Scripts/versiongenerate.py", "$(SRCROOT)/../configure.ac", ); name = "Generate Version.h"; outputPaths = ( "$(PROJECT_TEMP_DIR)/Version.h", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/usr/bin/python Scripts/versiongenerate.py ../ $PROJECT_TEMP_DIR"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 40899F400FFA7184000B29AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4089A0100FFACEFC000B29AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */, 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C848F7101A209C0083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C848FF101A21150083642A /* gtest-all.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C84908101A217E0083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C84915101A21DF0083642A /* gtest_main.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C8497F101A36850083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C84980101A36850083642A /* gtest_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 40C8498E101A36A60083642A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40C8498F101A36A60083642A /* sample1.cc in Sources */, 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D07F2C10486CC7A007CD1D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40899F420FFA7184000B29AE /* gtest_unittest-framework */; targetProxy = 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */; }; 4089A0980FFAD34A000B29AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */; targetProxy = 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */; }; 408BEC101046CFE900DEF522 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */; }; 40C44AE60E379922008FCC51 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C44ADC0E3798F4008FCC51 /* Version Info */; targetProxy = 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */; }; 40C8497B101A36850083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 40C8497C101A36850083642A /* PBXContainerItemProxy */; }; 40C8497D101A36850083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8497E101A36850083642A /* PBXContainerItemProxy */; }; 40C8498A101A36A60083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C848F9101A209C0083642A /* gtest-static */; targetProxy = 40C8498B101A36A60083642A /* PBXContainerItemProxy */; }; 40C8498C101A36A60083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8498D101A36A60083642A /* PBXContainerItemProxy */; }; 40C8499C101A36DC0083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8490A101A217E0083642A /* gtest_main-static */; targetProxy = 40C8499B101A36DC0083642A /* PBXContainerItemProxy */; }; 40C8499E101A36E50083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; targetProxy = 40C8499D101A36E50083642A /* PBXContainerItemProxy */; }; 40C849A0101A36F10083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */; targetProxy = 40C8499F101A36F10083642A /* PBXContainerItemProxy */; }; 40C849F7101A43440083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C8497A101A36850083642A /* gtest_unittest-static */; targetProxy = 40C849F6101A43440083642A /* PBXContainerItemProxy */; }; 40C849F9101A43490083642A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 40C84989101A36A60083642A /* sample1_unittest-static */; targetProxy = 40C849F8101A43490083642A /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 3B238F600E828B5400846E11 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = Check; SDKROOT = macosx; }; name = Debug; }; 3B238F610E828B5400846E11 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = Check; SDKROOT = macosx; ZERO_LINK = NO; }; name = Release; }; 40899F450FFA7185000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; SDKROOT = macosx; }; name = Debug; }; 40899F460FFA7185000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; SDKROOT = macosx; }; name = Release; }; 4089A0150FFACEFD000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-framework"; SDKROOT = macosx; }; name = Debug; }; 4089A0160FFACEFD000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-framework"; SDKROOT = macosx; }; name = Release; }; 40C44ADF0E3798F4008FCC51 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = gtest; SDKROOT = macosx; TARGET_NAME = gtest; }; name = Debug; }; 40C44AE00E3798F4008FCC51 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = gtest; SDKROOT = macosx; TARGET_NAME = gtest; }; name = Release; }; 40C848FB101A209D0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; SDKROOT = macosx; }; name = Debug; }; 40C848FC101A209D0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; SDKROOT = macosx; }; name = Release; }; 40C8490E101A217F0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; SDKROOT = macosx; }; name = Debug; }; 40C8490F101A217F0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; SDKROOT = macosx; }; name = Release; }; 40C84985101A36850083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; SDKROOT = macosx; }; name = Debug; }; 40C84986101A36850083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; SDKROOT = macosx; }; name = Release; }; 40C84995101A36A60083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-static"; SDKROOT = macosx; }; name = Debug; }; 40C84996101A36A60083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-static"; SDKROOT = macosx; }; name = Release; }; 4FADC24308B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 4FADC24408B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 4FADC24708B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */; buildSettings = { }; name = Debug; }; 4FADC24808B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */; buildSettings = { }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */ = { isa = XCConfigurationList; buildConfigurations = ( 3B238F600E828B5400846E11 /* Debug */, 3B238F610E828B5400846E11 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 40899F450FFA7185000B29AE /* Debug */, 40899F460FFA7185000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4089A0150FFACEFD000B29AE /* Debug */, 4089A0160FFACEFD000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C44ADF0E3798F4008FCC51 /* Debug */, 40C44AE00E3798F4008FCC51 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C848FB101A209D0083642A /* Debug */, 40C848FC101A209D0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C8490E101A217F0083642A /* Debug */, 40C8490F101A217F0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84985101A36850083642A /* Debug */, 40C84986101A36850083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84995101A36A60083642A /* Debug */, 40C84996101A36A60083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24308B4156D00ABE55E /* Debug */, 4FADC24408B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24708B4156D00ABE55E /* Debug */, 4FADC24808B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; } mongo-cxx-driver-legacy-1.1.2/src/third_party/jsoncpp/000077500000000000000000000000001273231111400227545ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/jsoncpp/json.h000066400000000000000000001711561273231111400241110ustar00rootroot00000000000000/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). /// It is intented to be used with #include // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// /* The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... The author (Baptiste Lepilleur) explicitly disclaims copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License The full text of the MIT License follows: ======================================================================== Copyright (c) 2007-2010 Baptiste Lepilleur 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. ======================================================================== (END LICENSE TEXT) The MIT license is compatible with both the GPL and commercial software, affording one all of the rights of Public Domain with the minor nuisance of being required to keep the above copyright notice and license text in the source code. Note also that by accepting the Public Domain "license" you can re-license your copy using whatever license you like. */ // ////////////////////////////////////////////////////////////////////// // End of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// #ifndef JSON_AMALGATED_H_INCLUDED # define JSON_AMALGATED_H_INCLUDED /// If defined, indicates that the source file is amalgated /// to prevent private header inclusion. #define JSON_IS_AMALGAMATION // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/config.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 /// If defined, indicates that json may leverage CppTL library //# define JSON_USE_CPPTL 1 /// If defined, indicates that cpptl vector based map should be used instead of /// std::map /// as Value container. //# define JSON_USE_CPPTL_SMALLMAP 1 /// If defined, indicates that Json specific container should be used /// (hash table & simple deque container with customizable allocator). /// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 //# define JSON_VALUE_USE_INTERNAL_MAP 1 /// Force usage of standard new/malloc based allocator instead of memory pool /// based allocator. /// The memory pools allocator used optimization (initializing Value and /// ValueInternalLink /// as if it was a POD) that may cause some validation tool to report errors. /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 // If non-zero, the library uses exceptions to report bad input instead of C // assertion macros. The default is to use exceptions. #ifndef JSON_USE_EXCEPTION #define JSON_USE_EXCEPTION 1 #endif /// If defined, indicates that the source file is amalgated /// to prevent private header inclusion. /// Remarks: it is automatically defined in the generated amalgated header. // #define JSON_IS_AMALGAMATION #ifdef JSON_IN_CPPTL #include #ifndef JSON_USE_CPPTL #define JSON_USE_CPPTL 1 #endif #endif #ifdef JSON_IN_CPPTL #define JSON_API CPPTL_API #elif defined(JSON_DLL_BUILD) #if defined(_MSC_VER) #define JSON_API __declspec(dllexport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) #elif defined(JSON_DLL) #if defined(_MSC_VER) #define JSON_API __declspec(dllimport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) #endif // ifdef JSON_IN_CPPTL #if !defined(JSON_API) #define JSON_API #endif // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for // integer // Storages, and 64 bits integer support is disabled. // #define JSON_NO_INT64 1 #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 // Microsoft Visual Studio 6 only support conversion from __int64 to double // (no conversion from unsigned __int64). #define JSON_USE_INT64_DOUBLE_CONVERSION 1 // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' // characters in the debug information) // All projects I've ever seen with VS6 were using this globally (not bothering // with pragma push/pop). #pragma warning(disable : 4786) #endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 #if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 /// Indicates that the following function is deprecated. #define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) #endif #if !defined(JSONCPP_DEPRECATED) #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) namespace Json { typedef int Int; typedef unsigned int UInt; #if defined(JSON_NO_INT64) typedef int LargestInt; typedef unsigned int LargestUInt; #undef JSON_HAS_INT64 #else // if defined(JSON_NO_INT64) // For Microsoft Visual use specific types as long long is not supported #if defined(_MSC_VER) // Microsoft Visual Studio typedef __int64 Int64; typedef unsigned __int64 UInt64; #else // if defined(_MSC_VER) // Other platforms, use long long typedef long long int Int64; typedef unsigned long long int UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; #define JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) } // end namespace Json #endif // JSON_CONFIG_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/config.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/forwards.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_FORWARDS_H_INCLUDED #define JSON_FORWARDS_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "config.h" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { // writer.h class FastWriter; class StyledWriter; // reader.h class Reader; // features.h class Features; // value.h typedef unsigned int ArrayIndex; class StaticString; class Path; class PathArgument; class Value; class ValueIteratorBase; class ValueIterator; class ValueConstIterator; #ifdef JSON_VALUE_USE_INTERNAL_MAP class ValueMapAllocator; class ValueInternalLink; class ValueInternalArray; class ValueInternalMap; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP } // namespace Json #endif // JSON_FORWARDS_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/forwards.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/features.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef CPPTL_JSON_FEATURES_H_INCLUDED #define CPPTL_JSON_FEATURES_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { /** \brief Configuration passed to reader and writer. * This configuration object can be used to force the Reader or Writer * to behave in a standard conforming way. */ class JSON_API Features { public: /** \brief A configuration that allows all features and assumes all strings * are UTF-8. * - C & C++ comments are allowed * - Root object can be any JSON value * - Assumes Value strings are encoded in UTF-8 */ static Features all(); /** \brief A configuration that is strictly compatible with the JSON * specification. * - Comments are forbidden. * - Root object must be either an array or an object value. * - Assumes Value strings are encoded in UTF-8 */ static Features strictMode(); /** \brief Initialize the configuration like JsonConfig::allFeatures; */ Features(); /// \c true if comments are allowed. Default: \c true. bool allowComments_; /// \c true if root must be either an array or an object value. Default: \c /// false. bool strictRoot_; /// \c true if dropped null placeholders are allowed. Default: \c false. bool allowDroppedNullPlaceholders_; /// \c true if numeric object key are allowed. Default: \c false. bool allowNumericKeys_; }; } // namespace Json #endif // CPPTL_JSON_FEATURES_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/features.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/value.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef CPPTL_JSON_H_INCLUDED #define CPPTL_JSON_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #ifndef JSON_USE_CPPTL_SMALLMAP #include #else #include #endif #ifdef JSON_USE_CPPTL #include #endif // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(push) #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) /** \brief JSON (JavaScript Object Notation). */ namespace Json { /** \brief Type of the value held by a Value object. */ enum ValueType { nullValue = 0, ///< 'null' value intValue, ///< signed integer value uintValue, ///< unsigned integer value realValue, ///< double value stringValue, ///< UTF-8 string value booleanValue, ///< bool value arrayValue, ///< array value (ordered list) objectValue ///< object value (collection of name/value pairs). }; enum CommentPlacement { commentBefore = 0, ///< a comment placed on the line before a value commentAfterOnSameLine, ///< a comment just after a value on the same line commentAfter, ///< a comment on the line after a value (only make sense for /// root value) numberOfCommentPlacement }; //# ifdef JSON_USE_CPPTL // typedef CppTL::AnyEnumerator EnumMemberNames; // typedef CppTL::AnyEnumerator EnumValues; //# endif /** \brief Lightweight wrapper to tag static string. * * Value constructor and objectValue member assignement takes advantage of the * StaticString and avoid the cost of string duplication when storing the * string or the member name. * * Example of usage: * \code * Json::Value aValue( StaticString("some text") ); * Json::Value object; * static const StaticString code("code"); * object[code] = 1234; * \endcode */ class JSON_API StaticString { public: explicit StaticString(const char *czstring) : str_(czstring) {} operator const char *() const { return str_; } const char *c_str() const { return str_; } private: const char *str_; }; /** \brief Represents a JSON value. * * This class is a discriminated union wrapper that can represents a: * - signed integer [range: Value::minInt - Value::maxInt] * - unsigned integer (range: 0 - Value::maxUInt) * - double * - UTF-8 string * - boolean * - 'null' * - an ordered list of Value * - collection of name/value pairs (javascript object) * * The type of the held value is represented by a #ValueType and * can be obtained using type(). * * values of an #objectValue or #arrayValue can be accessed using operator[]() *methods. * Non const methods will automatically create the a #nullValue element * if it does not exist. * The sequence of an #arrayValue will be automatically resize and initialized * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. * * The get() methods can be used to obtanis default value in the case the *required element * does not exist. * * It is possible to iterate over the list of a #objectValue values using * the getMemberNames() method. */ class JSON_API Value { friend class ValueIteratorBase; #ifdef JSON_VALUE_USE_INTERNAL_MAP friend class ValueInternalLink; friend class ValueInternalMap; #endif public: typedef std::vector Members; typedef ValueIterator iterator; typedef ValueConstIterator const_iterator; typedef Json::UInt UInt; typedef Json::Int Int; #if defined(JSON_HAS_INT64) typedef Json::UInt64 UInt64; typedef Json::Int64 Int64; #endif // defined(JSON_HAS_INT64) typedef Json::LargestInt LargestInt; typedef Json::LargestUInt LargestUInt; typedef Json::ArrayIndex ArrayIndex; static const Value& null; /// Minimum signed integer value that can be stored in a Json::Value. static const LargestInt minLargestInt; /// Maximum signed integer value that can be stored in a Json::Value. static const LargestInt maxLargestInt; /// Maximum unsigned integer value that can be stored in a Json::Value. static const LargestUInt maxLargestUInt; /// Minimum signed int value that can be stored in a Json::Value. static const Int minInt; /// Maximum signed int value that can be stored in a Json::Value. static const Int maxInt; /// Maximum unsigned int value that can be stored in a Json::Value. static const UInt maxUInt; #if defined(JSON_HAS_INT64) /// Minimum signed 64 bits int value that can be stored in a Json::Value. static const Int64 minInt64; /// Maximum signed 64 bits int value that can be stored in a Json::Value. static const Int64 maxInt64; /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. static const UInt64 maxUInt64; #endif // defined(JSON_HAS_INT64) private: #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION #ifndef JSON_VALUE_USE_INTERNAL_MAP class CZString { public: enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; CZString(ArrayIndex index); CZString(const char *cstr, DuplicationPolicy allocate); CZString(const CZString &other); ~CZString(); CZString &operator=(const CZString &other); bool operator<(const CZString &other) const; bool operator==(const CZString &other) const; ArrayIndex index() const; const char *c_str() const; bool isStaticString() const; private: void swap(CZString &other); const char *cstr_; ArrayIndex index_; }; public: #ifndef JSON_USE_CPPTL_SMALLMAP typedef std::map ObjectValues; #else typedef CppTL::SmallMap ObjectValues; #endif // ifndef JSON_USE_CPPTL_SMALLMAP #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION public: /** \brief Create a default Value of the given type. This is a very useful constructor. To create an empty array, pass arrayValue. To create an empty object, pass objectValue. Another Value can then be set to this one by assignment. This is useful since clear() and resize() will not alter types. Examples: \code Json::Value null_value; // null Json::Value arr_value(Json::arrayValue); // [] Json::Value obj_value(Json::objectValue); // {} \endcode */ Value(ValueType type = nullValue); Value(Int value); Value(UInt value); #if defined(JSON_HAS_INT64) Value(Int64 value); Value(UInt64 value); #endif // if defined(JSON_HAS_INT64) Value(double value); Value(const char *value); Value(const char *beginValue, const char *endValue); /** \brief Constructs a value from a static string. * Like other value string constructor but do not duplicate the string for * internal storage. The given string must remain alive after the call to this * constructor. * Example of usage: * \code * Json::Value aValue( StaticString("some text") ); * \endcode */ Value(const StaticString &value); Value(const std::string &value); #ifdef JSON_USE_CPPTL Value(const CppTL::ConstString &value); #endif Value(bool value); Value(const Value &other); ~Value(); Value &operator=(const Value &other); /// Swap values. /// \note Currently, comments are intentionally not swapped, for /// both logic and efficiency. void swap(Value &other); ValueType type() const; bool operator<(const Value &other) const; bool operator<=(const Value &other) const; bool operator>=(const Value &other) const; bool operator>(const Value &other) const; bool operator==(const Value &other) const; bool operator!=(const Value &other) const; int compare(const Value &other) const; const char *asCString() const; std::string asString() const; #ifdef JSON_USE_CPPTL CppTL::ConstString asConstString() const; #endif Int asInt() const; UInt asUInt() const; #if defined(JSON_HAS_INT64) Int64 asInt64() const; UInt64 asUInt64() const; #endif // if defined(JSON_HAS_INT64) LargestInt asLargestInt() const; LargestUInt asLargestUInt() const; float asFloat() const; double asDouble() const; bool asBool() const; bool isNull() const; bool isBool() const; bool isInt() const; bool isInt64() const; bool isUInt() const; bool isUInt64() const; bool isIntegral() const; bool isDouble() const; bool isNumeric() const; bool isString() const; bool isArray() const; bool isObject() const; bool isConvertibleTo(ValueType other) const; /// Number of values in array or object ArrayIndex size() const; /// \brief Return true if empty array, empty object, or null; /// otherwise, false. bool empty() const; /// Return isNull() bool operator!() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue /// \post type() is unchanged void clear(); /// Resize the array to size elements. /// New elements are initialized to null. /// May only be called on nullValue or arrayValue. /// \pre type() is arrayValue or nullValue /// \post type() is arrayValue void resize(ArrayIndex size); /// Access an array element (zero based index ). /// If the array contains less than index element, then null value are /// inserted /// in the array so that its size is index+1. /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) Value &operator[](ArrayIndex index); /// Access an array element (zero based index ). /// If the array contains less than index element, then null value are /// inserted /// in the array so that its size is index+1. /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) Value &operator[](int index); /// Access an array element (zero based index ) /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) const Value &operator[](ArrayIndex index) const; /// Access an array element (zero based index ) /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) const Value &operator[](int index) const; /// If the array contains at least index+1 elements, returns the element /// value, /// otherwise returns defaultValue. Value get(ArrayIndex index, const Value &defaultValue) const; /// Return true if index < size(). bool isValidIndex(ArrayIndex index) const; /// \brief Append value to array at the end. /// /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value &append(const Value &value); /// Access an object value by name, create a null member if it does not exist. Value &operator[](const char *key); /// Access an object value by name, returns null if there is no member with /// that name. const Value &operator[](const char *key) const; /// Access an object value by name, create a null member if it does not exist. Value &operator[](const std::string &key); /// Access an object value by name, returns null if there is no member with /// that name. const Value &operator[](const std::string &key) const; /** \brief Access an object value by name, create a null member if it does not exist. * If the object as no entry for that name, then the member name used to store * the new entry is not duplicated. * Example of use: * \code * Json::Value object; * static const StaticString code("code"); * object[code] = 1234; * \endcode */ Value &operator[](const StaticString &key); #ifdef JSON_USE_CPPTL /// Access an object value by name, create a null member if it does not exist. Value &operator[](const CppTL::ConstString &key); /// Access an object value by name, returns null if there is no member with /// that name. const Value &operator[](const CppTL::ConstString &key) const; #endif /// Return the member named key if it exist, defaultValue otherwise. Value get(const char *key, const Value &defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. Value get(const std::string &key, const Value &defaultValue) const; #ifdef JSON_USE_CPPTL /// Return the member named key if it exist, defaultValue otherwise. Value get(const CppTL::ConstString &key, const Value &defaultValue) const; #endif /// \brief Remove and return the named member. /// /// Do nothing if it did not exist. /// \return the removed Value, or null. /// \pre type() is objectValue or nullValue /// \post type() is unchanged Value removeMember(const char *key); /// Same as removeMember(const char*) Value removeMember(const std::string &key); /// Return true if the object has a member named key. bool isMember(const char *key) const; /// Return true if the object has a member named key. bool isMember(const std::string &key) const; #ifdef JSON_USE_CPPTL /// Return true if the object has a member named key. bool isMember(const CppTL::ConstString &key) const; #endif /// \brief Return a list of the member names. /// /// If null, return an empty list. /// \pre type() is objectValue or nullValue /// \post if type() was nullValue, it remains nullValue Members getMemberNames() const; //# ifdef JSON_USE_CPPTL // EnumMemberNames enumMemberNames() const; // EnumValues enumValues() const; //# endif /// Comments must be //... or /* ... */ void setComment(const char *comment, CommentPlacement placement); /// Comments must be //... or /* ... */ void setComment(const std::string &comment, CommentPlacement placement); bool hasComment(CommentPlacement placement) const; /// Include delimiters and embedded newlines. std::string getComment(CommentPlacement placement) const; std::string toStyledString() const; const_iterator begin() const; const_iterator end() const; iterator begin(); iterator end(); // Accessors for the [start, limit) range of bytes within the JSON text from // which this value was parsed, if any. void setOffsetStart(size_t start); void setOffsetLimit(size_t limit); size_t getOffsetStart() const; size_t getOffsetLimit() const; private: Value &resolveReference(const char *key, bool isStatic); #ifdef JSON_VALUE_USE_INTERNAL_MAP inline bool isItemAvailable() const { return itemIsUsed_ == 0; } inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; } inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; } inline void setMemberNameIsStatic(bool isStatic) { memberNameIsStatic_ = isStatic ? 1 : 0; } #endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP private: struct CommentInfo { CommentInfo(); ~CommentInfo(); void setComment(const char *text); char *comment_; }; // struct MemberNamesTransform //{ // typedef const char *result_type; // const char *operator()( const CZString &name ) const // { // return name.c_str(); // } //}; union ValueHolder { LargestInt int_; LargestUInt uint_; double real_; bool bool_; char *string_; #ifdef JSON_VALUE_USE_INTERNAL_MAP ValueInternalArray *array_; ValueInternalMap *map_; #else ObjectValues *map_; #endif } value_; ValueType type_ : 8; int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. #ifdef JSON_VALUE_USE_INTERNAL_MAP unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. #endif CommentInfo *comments_; // [start, limit) byte offsets in the source JSON text from which this Value // was extracted. size_t start_; size_t limit_; }; /** \brief Experimental and untested: represents an element of the "path" to * access a node. */ class JSON_API PathArgument { public: friend class Path; PathArgument(); PathArgument(ArrayIndex index); PathArgument(const char *key); PathArgument(const std::string &key); private: enum Kind { kindNone = 0, kindIndex, kindKey }; std::string key_; ArrayIndex index_; Kind kind_; }; /** \brief Experimental and untested: represents a "path" to access a node. * * Syntax: * - "." => root node * - ".[n]" => elements at index 'n' of root node (an array value) * - ".name" => member named 'name' of root node (an object value) * - ".name1.name2.name3" * - ".[0][1][2].name1[3]" * - ".%" => member name is provided as parameter * - ".[%]" => index is provied as parameter */ class JSON_API Path { public: Path(const std::string &path, const PathArgument &a1 = PathArgument(), const PathArgument &a2 = PathArgument(), const PathArgument &a3 = PathArgument(), const PathArgument &a4 = PathArgument(), const PathArgument &a5 = PathArgument()); const Value &resolve(const Value &root) const; Value resolve(const Value &root, const Value &defaultValue) const; /// Creates the "path" to access the specified node and returns a reference on /// the node. Value &make(Value &root) const; private: typedef std::vector InArgs; typedef std::vector Args; void makePath(const std::string &path, const InArgs &in); void addPathInArg(const std::string &path, const InArgs &in, InArgs::const_iterator &itInArg, PathArgument::Kind kind); void invalidPath(const std::string &path, int location); Args args_; }; #ifdef JSON_VALUE_USE_INTERNAL_MAP /** \brief Allocator to customize Value internal map. * Below is an example of a simple implementation (default implementation actually * use memory pool for speed). * \code class DefaultValueMapAllocator : public ValueMapAllocator { public: // overridden from ValueMapAllocator virtual ValueInternalMap *newMap() { return new ValueInternalMap(); } virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) { return new ValueInternalMap( other ); } virtual void destructMap( ValueInternalMap *map ) { delete map; } virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) { return new ValueInternalLink[size]; } virtual void releaseMapBuckets( ValueInternalLink *links ) { delete [] links; } virtual ValueInternalLink *allocateMapLink() { return new ValueInternalLink(); } virtual void releaseMapLink( ValueInternalLink *link ) { delete link; } }; * \endcode */ class JSON_API ValueMapAllocator { public: virtual ~ValueMapAllocator(); virtual ValueInternalMap *newMap() = 0; virtual ValueInternalMap *newMapCopy(const ValueInternalMap &other) = 0; virtual void destructMap(ValueInternalMap *map) = 0; virtual ValueInternalLink *allocateMapBuckets(unsigned int size) = 0; virtual void releaseMapBuckets(ValueInternalLink *links) = 0; virtual ValueInternalLink *allocateMapLink() = 0; virtual void releaseMapLink(ValueInternalLink *link) = 0; }; /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). * \internal previous_ & next_ allows for bidirectional traversal. */ class JSON_API ValueInternalLink { public: enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. enum InternalFlags { flagAvailable = 0, flagUsed = 1 }; ValueInternalLink(); ~ValueInternalLink(); Value items_[itemPerLink]; char *keys_[itemPerLink]; ValueInternalLink *previous_; ValueInternalLink *next_; }; /** \brief A linked page based hash-table implementation used internally by *Value. * \internal ValueInternalMap is a tradional bucket based hash-table, with a *linked * list in each bucket to handle collision. There is an addional twist in that * each node of the collision linked list is a page containing a fixed amount of * value. This provides a better compromise between memory usage and speed. * * Each bucket is made up of a chained list of ValueInternalLink. The last * link of a given bucket can be found in the 'previous_' field of the following *bucket. * The last link of the last bucket is stored in tailLink_ as it has no *following bucket. * Only the last link of a bucket may contains 'available' item. The last link *always * contains at least one element unless is it the bucket one very first link. */ class JSON_API ValueInternalMap { friend class ValueIteratorBase; friend class Value; public: typedef unsigned int HashKey; typedef unsigned int BucketIndex; #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION struct IteratorState { IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {} ValueInternalMap *map_; ValueInternalLink *link_; BucketIndex itemIndex_; BucketIndex bucketIndex_; }; #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ValueInternalMap(); ValueInternalMap(const ValueInternalMap &other); ValueInternalMap &operator=(const ValueInternalMap &other); ~ValueInternalMap(); void swap(ValueInternalMap &other); BucketIndex size() const; void clear(); bool reserveDelta(BucketIndex growth); bool reserve(BucketIndex newItemCount); const Value *find(const char *key) const; Value *find(const char *key); Value &resolveReference(const char *key, bool isStatic); void remove(const char *key); void doActualRemove(ValueInternalLink *link, BucketIndex index, BucketIndex bucketIndex); ValueInternalLink *&getLastLinkInBucket(BucketIndex bucketIndex); Value &setNewItem(const char *key, bool isStatic, ValueInternalLink *link, BucketIndex index); Value &unsafeAdd(const char *key, bool isStatic, HashKey hashedKey); HashKey hash(const char *key) const; int compare(const ValueInternalMap &other) const; private: void makeBeginIterator(IteratorState &it) const; void makeEndIterator(IteratorState &it) const; static bool equals(const IteratorState &x, const IteratorState &other); static void increment(IteratorState &iterator); static void incrementBucket(IteratorState &iterator); static void decrement(IteratorState &iterator); static const char *key(const IteratorState &iterator); static const char *key(const IteratorState &iterator, bool &isStatic); static Value &value(const IteratorState &iterator); static int distance(const IteratorState &x, const IteratorState &y); private: ValueInternalLink *buckets_; ValueInternalLink *tailLink_; BucketIndex bucketsSize_; BucketIndex itemCount_; }; /** \brief A simplified deque implementation used internally by Value. * \internal * It is based on a list of fixed "page", each page contains a fixed number of *items. * Instead of using a linked-list, a array of pointer is used for fast item *look-up. * Look-up for an element is as follow: * - compute page index: pageIndex = itemIndex / itemsPerPage * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] * * Insertion is amortized constant time (only the array containing the index of *pointers * need to be reallocated when items are appended). */ class JSON_API ValueInternalArray { friend class Value; friend class ValueIteratorBase; public: enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. typedef Value::ArrayIndex ArrayIndex; typedef unsigned int PageIndex; #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION struct IteratorState // Must be a POD { IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {} ValueInternalArray *array_; Value **currentPageIndex_; unsigned int currentItemIndex_; }; #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ValueInternalArray(); ValueInternalArray(const ValueInternalArray &other); ValueInternalArray &operator=(const ValueInternalArray &other); ~ValueInternalArray(); void swap(ValueInternalArray &other); void clear(); void resize(ArrayIndex newSize); Value &resolveReference(ArrayIndex index); Value *find(ArrayIndex index) const; ArrayIndex size() const; int compare(const ValueInternalArray &other) const; private: static bool equals(const IteratorState &x, const IteratorState &other); static void increment(IteratorState &iterator); static void decrement(IteratorState &iterator); static Value &dereference(const IteratorState &iterator); static Value &unsafeDereference(const IteratorState &iterator); static int distance(const IteratorState &x, const IteratorState &y); static ArrayIndex indexOf(const IteratorState &iterator); void makeBeginIterator(IteratorState &it) const; void makeEndIterator(IteratorState &it) const; void makeIterator(IteratorState &it, ArrayIndex index) const; void makeIndexValid(ArrayIndex index); Value **pages_; ArrayIndex size_; PageIndex pageCount_; }; /** \brief Experimental: do not use. Allocator to customize Value internal array. * Below is an example of a simple implementation (actual implementation use * memory pool). \code class DefaultValueArrayAllocator : public ValueArrayAllocator { public: // overridden from ValueArrayAllocator virtual ~DefaultValueArrayAllocator() { } virtual ValueInternalArray *newArray() { return new ValueInternalArray(); } virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) { return new ValueInternalArray( other ); } virtual void destruct( ValueInternalArray *array ) { delete array; } virtual void reallocateArrayPageIndex( Value **&indexes, ValueInternalArray::PageIndex &indexCount, ValueInternalArray::PageIndex minNewIndexCount ) { ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; if ( minNewIndexCount > newIndexCount ) newIndexCount = minNewIndexCount; void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); if ( !newIndexes ) throw std::bad_alloc(); indexCount = newIndexCount; indexes = static_cast( newIndexes ); } virtual void releaseArrayPageIndex( Value **indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free( indexes ); } virtual Value *allocateArrayPage() { return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); } virtual void releaseArrayPage( Value *value ) { if ( value ) free( value ); } }; \endcode */ class JSON_API ValueArrayAllocator { public: virtual ~ValueArrayAllocator(); virtual ValueInternalArray *newArray() = 0; virtual ValueInternalArray *newArrayCopy(const ValueInternalArray &other) = 0; virtual void destructArray(ValueInternalArray *array) = 0; /** \brief Reallocate array page index. * Reallocates an array of pointer on each page. * \param indexes [input] pointer on the current index. May be \c NULL. * [output] pointer on the new index of at least * \a minNewIndexCount pages. * \param indexCount [input] current number of pages in the index. * [output] number of page the reallocated index can handle. * \b MUST be >= \a minNewIndexCount. * \param minNewIndexCount Minimum number of page the new index must be able * to * handle. */ virtual void reallocateArrayPageIndex(Value **&indexes, ValueInternalArray::PageIndex &indexCount, ValueInternalArray::PageIndex minNewIndexCount) = 0; virtual void releaseArrayPageIndex(Value **indexes, ValueInternalArray::PageIndex indexCount) = 0; virtual Value *allocateArrayPage() = 0; virtual void releaseArrayPage(Value *value) = 0; }; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP /** \brief base class for Value iterators. * */ class JSON_API ValueIteratorBase { public: typedef std::bidirectional_iterator_tag iterator_category; typedef unsigned int size_t; typedef int difference_type; typedef ValueIteratorBase SelfType; ValueIteratorBase(); #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueIteratorBase(const Value::ObjectValues::iterator ¤t); #else ValueIteratorBase(const ValueInternalArray::IteratorState &state); ValueIteratorBase(const ValueInternalMap::IteratorState &state); #endif bool operator==(const SelfType &other) const { return isEqual(other); } bool operator!=(const SelfType &other) const { return !isEqual(other); } difference_type operator-(const SelfType &other) const { return computeDistance(other); } /// Return either the index or the member name of the referenced value as a /// Value. Value key() const; /// Return the index of the referenced Value. -1 if it is not an arrayValue. UInt index() const; /// Return the member name of the referenced Value. "" if it is not an /// objectValue. const char *memberName() const; protected: Value &deref() const; void increment(); void decrement(); difference_type computeDistance(const SelfType &other) const; bool isEqual(const SelfType &other) const; void copy(const SelfType &other); private: #ifndef JSON_VALUE_USE_INTERNAL_MAP Value::ObjectValues::iterator current_; // Indicates that iterator is for a null value. bool isNull_; #else union { ValueInternalArray::IteratorState array_; ValueInternalMap::IteratorState map_; } iterator_; bool isArray_; #endif }; /** \brief const iterator for object and array value. * */ class JSON_API ValueConstIterator : public ValueIteratorBase { friend class Value; public: typedef const Value value_type; typedef unsigned int size_t; typedef int difference_type; typedef const Value &reference; typedef const Value *pointer; typedef ValueConstIterator SelfType; ValueConstIterator(); private: /*! \internal Use by Value to create an iterator. */ #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueConstIterator(const Value::ObjectValues::iterator ¤t); #else ValueConstIterator(const ValueInternalArray::IteratorState &state); ValueConstIterator(const ValueInternalMap::IteratorState &state); #endif public: SelfType &operator=(const ValueIteratorBase &other); SelfType operator++(int) { SelfType temp(*this); ++*this; return temp; } SelfType operator--(int) { SelfType temp(*this); --*this; return temp; } SelfType &operator--() { decrement(); return *this; } SelfType &operator++() { increment(); return *this; } reference operator*() const { return deref(); } }; /** \brief Iterator for object and array value. */ class JSON_API ValueIterator : public ValueIteratorBase { friend class Value; public: typedef Value value_type; typedef unsigned int size_t; typedef int difference_type; typedef Value &reference; typedef Value *pointer; typedef ValueIterator SelfType; ValueIterator(); ValueIterator(const ValueConstIterator &other); ValueIterator(const ValueIterator &other); private: /*! \internal Use by Value to create an iterator. */ #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueIterator(const Value::ObjectValues::iterator ¤t); #else ValueIterator(const ValueInternalArray::IteratorState &state); ValueIterator(const ValueInternalMap::IteratorState &state); #endif public: SelfType &operator=(const SelfType &other); SelfType operator++(int) { SelfType temp(*this); ++*this; return temp; } SelfType operator--(int) { SelfType temp(*this); --*this; return temp; } SelfType &operator--() { decrement(); return *this; } SelfType &operator++() { increment(); return *this; } reference operator*() const { return deref(); } }; } // namespace Json #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // CPPTL_JSON_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/value.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/reader.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef CPPTL_JSON_READER_H_INCLUDED #define CPPTL_JSON_READER_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "features.h" #include "value.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(push) #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) namespace Json { /** \brief Unserialize a JSON document into a *Value. * */ class JSON_API Reader { public: typedef char Char; typedef const Char *Location; /** \brief An error tagged with where in the JSON text it was encountered. * * The offsets give the [start, limit) range of bytes within the text. Note * that this is bytes, not codepoints. * */ struct StructuredError { size_t offset_start; size_t offset_limit; std::string message; }; /** \brief Constructs a Reader allowing all features * for parsing. */ Reader(); /** \brief Constructs a Reader allowing the specified feature set * for parsing. */ Reader(const Features &features); /** \brief Read a Value from a JSON * document. * \param document UTF-8 encoded string containing the document to read. * \param root [out] Contains the root value of the document if it was * successfully parsed. * \param collectComments \c true to collect comment and allow writing them * back during * serialization, \c false to discard comments. * This parameter is ignored if * Features::allowComments_ * is \c false. * \return \c true if the document was successfully parsed, \c false if an * error occurred. */ bool parse(const std::string &document, Value &root, bool collectComments = true); /** \brief Read a Value from a JSON document. * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. \ Must be >= beginDoc. * \param root [out] Contains the root value of the document if it was * successfully parsed. * \param collectComments \c true to collect comment and allow writing them back during * serialization, \c false to discard comments. * This parameter is ignored if Features::allowComments_ * is \c false. * \return \c true if the document was successfully parsed, \c false if an error occurred. */ bool parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments = true); /// \brief Parse from input stream. /// \see Json::operator>>(std::istream&, Json::Value&). bool parse(std::istream &is, Value &root, bool collectComments = true); /** \brief Returns a user friendly string that list errors in the parsed * document. * \return Formatted error message with the list of errors with their location * in * the parsed document. An empty string is returned if no error * occurred * during parsing. * \deprecated Use getFormattedErrorMessages() instead (typo fix). */ JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") std::string getFormatedErrorMessages() const; /** \brief Returns a user friendly string that list errors in the parsed * document. * \return Formatted error message with the list of errors with their location * in * the parsed document. An empty string is returned if no error * occurred * during parsing. */ std::string getFormattedErrorMessages() const; /** \brief Returns a vector of structured erros encounted while parsing. * \return A (possibly empty) vector of StructuredError objects. Currently * only one error can be returned, but the caller should tolerate * multiple * errors. This can occur if the parser recovers from a non-fatal * parse error and then encounters additional errors. */ std::vector getStructuredErrors() const; private: enum TokenType { tokenEndOfStream = 0, tokenObjectBegin, tokenObjectEnd, tokenArrayBegin, tokenArrayEnd, tokenString, tokenNumber, tokenTrue, tokenFalse, tokenNull, tokenArraySeparator, tokenMemberSeparator, tokenComment, tokenError }; class Token { public: TokenType type_; Location start_; Location end_; }; class ErrorInfo { public: Token token_; std::string message_; Location extra_; }; typedef std::deque Errors; bool expectToken(TokenType type, Token &token, const char *message); bool readToken(Token &token); void skipSpaces(); bool match(Location pattern, int patternLength); bool readComment(); bool readCStyleComment(); bool readCppStyleComment(); bool readString(); void readNumber(); bool readValue(); bool readObject(Token &token); bool readArray(Token &token); bool decodeNumber(Token &token); bool decodeNumber(Token &token, Value &decoded); bool decodeString(Token &token); bool decodeString(Token &token, std::string &decoded); bool decodeDouble(Token &token); bool decodeDouble(Token &token, Value &decoded); bool decodeUnicodeCodePoint(Token &token, Location ¤t, Location end, unsigned int &unicode); bool decodeUnicodeEscapeSequence(Token &token, Location ¤t, Location end, unsigned int &unicode); bool addError(const std::string &message, Token &token, Location extra = 0); bool recoverFromError(TokenType skipUntilToken); bool addErrorAndRecover(const std::string &message, Token &token, TokenType skipUntilToken); void skipUntilSpace(); Value ¤tValue(); Char getNextChar(); void getLocationLineAndColumn(Location location, int &line, int &column) const; std::string getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); void skipCommentTokens(Token &token); typedef std::stack Nodes; Nodes nodes_; Errors errors_; std::string document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value *lastValue_; std::string commentsBefore_; Features features_; bool collectComments_; }; /** \brief Read from 'sin' into 'root'. Always keep comments from the input JSON. This can be used to read a file into a particular sub-object. For example: \code Json::Value root; cin >> root["dir"]["file"]; cout << root; \endcode Result: \verbatim { "dir": { "file": { // The input stream JSON would be nested here. } } } \endverbatim \throw std::exception on parse error. \see Json::operator<<() */ JSON_API std::istream &operator>>(std::istream &, Value &); } // namespace Json #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // CPPTL_JSON_READER_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/reader.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/writer.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_WRITER_H_INCLUDED #define JSON_WRITER_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "value.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(push) #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) namespace Json { class Value; /** \brief Abstract class for writers. */ class JSON_API Writer { public: virtual ~Writer(); virtual std::string write(const Value &root) = 0; }; /** \brief Outputs a Value in JSON format *without formatting (not human friendly). * * The JSON document is written in a single line. It is not intended for 'human' *consumption, * but may be usefull to support feature such as RPC where bandwith is limited. * \sa Reader, Value */ class JSON_API FastWriter : public Writer { public: FastWriter(); virtual ~FastWriter() {} void enableYAMLCompatibility(); /** \brief Drop the "null" string from the writer's output for nullValues. * Strictly speaking, this is not valid JSON. But when the output is being * fed to a browser's Javascript, it makes for smaller output and the * browser can handle the output just fine. */ void dropNullPlaceholders(); public: // overridden from Writer virtual std::string write(const Value &root); private: void writeValue(const Value &value); std::string document_; bool yamlCompatiblityEnabled_; bool dropNullPlaceholders_; }; /** \brief Writes a Value in JSON format in a *human friendly way. * * The rules for line break and indent are as follow: * - Object value: * - if empty then print {} without indent and line break * - if not empty the print '{', line break & indent, print one value per *line * and then unindent and line break and print '}'. * - Array value: * - if empty then print [] without indent and line break * - if the array contains no object value, empty array or some other value *types, * and all the values fit on one lines, then print the array on a single *line. * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * * If the Value have comments then they are outputed according to their *#CommentPlacement. * * \sa Reader, Value, Value::setComment() */ class JSON_API StyledWriter : public Writer { public: StyledWriter(); virtual ~StyledWriter() {} public: // overridden from Writer /** \brief Serialize a Value in JSON format. * \param root Value to serialize. * \return String containing the JSON document that represents the root value. */ virtual std::string write(const Value &root); private: void writeValue(const Value &value); void writeArrayValue(const Value &value); bool isMultineArray(const Value &value); void pushValue(const std::string &value); void writeIndent(); void writeWithIndent(const std::string &value); void indent(); void unindent(); void writeCommentBeforeValue(const Value &root); void writeCommentAfterValueOnSameLine(const Value &root); bool hasCommentForValue(const Value &value); static std::string normalizeEOL(const std::string &text); typedef std::vector ChildValues; ChildValues childValues_; std::string document_; std::string indentString_; int rightMargin_; int indentSize_; bool addChildValues_; }; /** \brief Writes a Value in JSON format in a human friendly way, to a stream rather than to a string. * * The rules for line break and indent are as follow: * - Object value: * - if empty then print {} without indent and line break * - if not empty the print '{', line break & indent, print one value per line * and then unindent and line break and print '}'. * - Array value: * - if empty then print [] without indent and line break * - if the array contains no object value, empty array or some other value types, * and all the values fit on one lines, then print the array on a single line. * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * * If the Value have comments then they are outputed according to their #CommentPlacement. * * \param indentation Each level will be indented by this amount extra. * \sa Reader, Value, Value::setComment() */ class JSON_API StyledStreamWriter { public: StyledStreamWriter(std::string indentation = "\t"); ~StyledStreamWriter() {} public: /** \brief Serialize a Value in JSON format. * \param out Stream to write to. (Can be ostringstream, e.g.) * \param root Value to serialize. * \note There is no point in deriving from Writer, since write() should not * return a value. */ void write(std::ostream &out, const Value &root); private: void writeValue(const Value &value); void writeArrayValue(const Value &value); bool isMultineArray(const Value &value); void pushValue(const std::string &value); void writeIndent(); void writeWithIndent(const std::string &value); void indent(); void unindent(); void writeCommentBeforeValue(const Value &root); void writeCommentAfterValueOnSameLine(const Value &root); bool hasCommentForValue(const Value &value); static std::string normalizeEOL(const std::string &text); typedef std::vector ChildValues; ChildValues childValues_; std::ostream *document_; std::string indentString_; int rightMargin_; std::string indentation_; bool addChildValues_; }; #if defined(JSON_HAS_INT64) std::string JSON_API valueToString(Int value); std::string JSON_API valueToString(UInt value); #endif // if defined(JSON_HAS_INT64) std::string JSON_API valueToString(LargestInt value); std::string JSON_API valueToString(LargestUInt value); std::string JSON_API valueToString(double value); std::string JSON_API valueToString(bool value); std::string JSON_API valueToQuotedString(const char *value); /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() JSON_API std::ostream &operator<<(std::ostream &, const Value &root); } // namespace Json #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // JSON_WRITER_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/writer.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: include/json/assertions.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED #define CPPTL_JSON_ASSERTIONS_H_INCLUDED #include #if !defined(JSON_IS_AMALGAMATION) #include "config.h" #endif // if !defined(JSON_IS_AMALGAMATION) #if JSON_USE_EXCEPTION #include #define JSON_ASSERT(condition) \ assert(condition); // @todo <= change this into an exception throw #define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message); #else // JSON_USE_EXCEPTION #define JSON_ASSERT(condition) assert(condition); // The call to assert() will show the failure message in debug builds. In // release bugs we write to invalid memory in order to crash hard, so that a // debugger or crash reporter gets the chance to take over. We still call exit() // afterward in order to tell the compiler that this macro doesn't return. #define JSON_FAIL_MESSAGE(message) \ { \ assert(false &&message); \ strcpy(reinterpret_cast(666), message); \ exit(123); \ } #endif #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) { \ JSON_FAIL_MESSAGE(message) \ } #endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED // ////////////////////////////////////////////////////////////////////// // End of content of file: include/json/assertions.h // ////////////////////////////////////////////////////////////////////// #endif //ifndef JSON_AMALGATED_H_INCLUDED mongo-cxx-driver-legacy-1.1.2/src/third_party/jsoncpp/jsoncpp.cpp000066400000000000000000003170451273231111400251460ustar00rootroot00000000000000/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). /// It is intented to be used with #include "dist/jsoncpp.cpp" // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// /* The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... The author (Baptiste Lepilleur) explicitly disclaims copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License The full text of the MIT License follows: ======================================================================== Copyright (c) 2007-2010 Baptiste Lepilleur 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. ======================================================================== (END LICENSE TEXT) The MIT license is compatible with both the GPL and commercial software, affording one all of the rights of Public Domain with the minor nuisance of being required to keep the above copyright notice and license text in the source code. Note also that by accepting the Public Domain "license" you can re-license your copy using whatever license you like. */ // ////////////////////////////////////////////////////////////////////// // End of content of file: LICENSE // ////////////////////////////////////////////////////////////////////// #include "json.h" // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_tool.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED /* This header provides common string manipulation support, such as UTF-8, * portable conversion from/to string... * * It is an internal header that must not be exposed. */ namespace Json { /// Converts a unicode code-point to UTF-8. static inline std::string codePointToUTF8(unsigned int cp) { std::string result; // based on description from http://en.wikipedia.org/wiki/UTF-8 if (cp <= 0x7f) { result.resize(1); result[0] = static_cast(cp); } else if (cp <= 0x7FF) { result.resize(2); result[1] = static_cast(0x80 | (0x3f & cp)); result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); } else if (cp <= 0xFFFF) { result.resize(3); result[2] = static_cast(0x80 | (0x3f & cp)); result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); } else if (cp <= 0x10FFFF) { result.resize(4); result[3] = static_cast(0x80 | (0x3f & cp)); result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); } return result; } /// Returns true if ch is a control character (in range [0,32[). static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } enum { /// Constant that specify the size of the buffer that must be passed to /// uintToString. uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 }; // Defines a char buffer for use with uintToString(). typedef char UIntToStringBuffer[uintToStringBufferSize]; /** Converts an unsigned integer to string. * @param value Unsigned interger to convert to string * @param current Input/Output string buffer. * Must have at least uintToStringBufferSize chars free. */ static inline void uintToString(LargestUInt value, char *¤t) { *--current = 0; do { *--current = char(value % 10) + '0'; value /= 10; } while (value != 0); } /** Change ',' to '.' everywhere in buffer. * * We had a sophisticated way, but it did not work in WinCE. * @see https://github.com/open-source-parsers/jsoncpp/pull/9 */ static inline void fixNumericLocale(char* begin, char* end) { while (begin < end) { if (*begin == ',') { *begin = '.'; } ++begin; } } } // namespace Json { #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED // vim: et ts=2 sts=2 sw=2 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_tool.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_reader.cpp // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2011 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) #include #include #include #include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif namespace Json { // Implementation of class Features // //////////////////////////////// Features::Features() : allowComments_(true), strictRoot_(false), allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} Features Features::all() { return Features(); } Features Features::strictMode() { Features features; features.allowComments_ = false; features.strictRoot_ = true; features.allowDroppedNullPlaceholders_ = false; features.allowNumericKeys_ = false; return features; } // Implementation of class Reader // //////////////////////////////// static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4) { return c == c1 || c == c2 || c == c3 || c == c4; } static inline bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5) { return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; } static bool containsNewLine(Reader::Location begin, Reader::Location end) { for (; begin < end; ++begin) if (*begin == '\n' || *begin == '\r') return true; return false; } // Class Reader // ////////////////////////////////////////////////////////////////// Reader::Reader() : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), lastValue_(), commentsBefore_(), features_(Features::all()), collectComments_() {} Reader::Reader(const Features &features) : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), lastValue_(), commentsBefore_(), features_(features), collectComments_() { } bool Reader::parse(const std::string &document, Value &root, bool collectComments) { document_ = document; const char *begin = document_.c_str(); const char *end = begin + document_.length(); return parse(begin, end, root, collectComments); } bool Reader::parse(std::istream &sin, Value &root, bool collectComments) { // std::istream_iterator begin(sin); // std::istream_iterator end; // Those would allow streamed input from a file, if parse() were a // template function. // Since std::string is reference-counted, this at least does not // create an extra copy. std::string doc; std::getline(sin, doc, (char)EOF); return parse(doc, root, collectComments); } bool Reader::parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments) { if (!features_.allowComments_) { collectComments = false; } begin_ = beginDoc; end_ = endDoc; collectComments_ = collectComments; current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; commentsBefore_ = ""; errors_.clear(); while (!nodes_.empty()) nodes_.pop(); nodes_.push(&root); bool successful = readValue(); Token token; skipCommentTokens(token); if (collectComments_ && !commentsBefore_.empty()) root.setComment(commentsBefore_, commentAfter); if (features_.strictRoot_) { if (!root.isArray() && !root.isObject()) { // Set error location to start of doc, ideally should be first token found // in doc token.type_ = tokenError; token.start_ = beginDoc; token.end_ = endDoc; addError( "A valid JSON document must be either an array or an object value.", token); return false; } } return successful; } bool Reader::readValue() { Token token; skipCommentTokens(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { // Remove newline characters at the end of the comments size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n"); if (lastNonNewline != std::string::npos) { commentsBefore_.erase(lastNonNewline + 1); } else { commentsBefore_.clear(); } currentValue().setComment(commentsBefore_, commentBefore); commentsBefore_ = ""; } switch (token.type_) { case tokenObjectBegin: successful = readObject(token); currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); break; case tokenString: successful = decodeString(token); break; case tokenTrue: currentValue() = true; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenFalse: currentValue() = false; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenNull: currentValue() = Value(); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); break; case tokenArraySeparator: if (features_.allowDroppedNullPlaceholders_) { // "Un-read" the current token and mark the current value as a null // token. current_--; currentValue() = Value(); currentValue().setOffsetStart(current_ - begin_ - 1); currentValue().setOffsetLimit(current_ - begin_); break; } // Else, fall through... default: currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } if (collectComments_) { lastValueEnd_ = current_; lastValue_ = ¤tValue(); } return successful; } void Reader::skipCommentTokens(Token &token) { if (features_.allowComments_) { do { readToken(token); } while (token.type_ == tokenComment); } else { readToken(token); } } bool Reader::expectToken(TokenType type, Token &token, const char *message) { readToken(token); if (token.type_ != type) return addError(message, token); return true; } bool Reader::readToken(Token &token) { skipSpaces(); token.start_ = current_; Char c = getNextChar(); bool ok = true; switch (c) { case '{': token.type_ = tokenObjectBegin; break; case '}': token.type_ = tokenObjectEnd; break; case '[': token.type_ = tokenArrayBegin; break; case ']': token.type_ = tokenArrayEnd; break; case '"': token.type_ = tokenString; ok = readString(); break; case '/': token.type_ = tokenComment; ok = readComment(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': token.type_ = tokenNumber; readNumber(); break; case 't': token.type_ = tokenTrue; ok = match("rue", 3); break; case 'f': token.type_ = tokenFalse; ok = match("alse", 4); break; case 'n': token.type_ = tokenNull; ok = match("ull", 3); break; case ',': token.type_ = tokenArraySeparator; break; case ':': token.type_ = tokenMemberSeparator; break; case 0: token.type_ = tokenEndOfStream; break; default: ok = false; break; } if (!ok) token.type_ = tokenError; token.end_ = current_; return true; } void Reader::skipSpaces() { while (current_ != end_) { Char c = *current_; if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++current_; else break; } } bool Reader::match(Location pattern, int patternLength) { if (end_ - current_ < patternLength) return false; int index = patternLength; while (index--) if (current_[index] != pattern[index]) return false; current_ += patternLength; return true; } bool Reader::readComment() { Location commentBegin = current_ - 1; Char c = getNextChar(); bool successful = false; if (c == '*') successful = readCStyleComment(); else if (c == '/') successful = readCppStyleComment(); if (!successful) return false; if (collectComments_) { CommentPlacement placement = commentBefore; if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { if (c != '*' || !containsNewLine(commentBegin, current_)) placement = commentAfterOnSameLine; } addComment(commentBegin, current_, placement); } return true; } void Reader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(std::string(begin, end), placement); } else { if (!commentsBefore_.empty()) commentsBefore_ += "\n"; commentsBefore_ += std::string(begin, end); } } bool Reader::readCStyleComment() { while (current_ != end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; } return getNextChar() == '/'; } bool Reader::readCppStyleComment() { while (current_ != end_) { Char c = getNextChar(); if (c == '\r' || c == '\n') break; } return true; } void Reader::readNumber() { while (current_ != end_) { if (!(*current_ >= '0' && *current_ <= '9') && !in(*current_, '.', 'e', 'E', '+', '-')) break; ++current_; } } bool Reader::readString() { Char c = 0; while (current_ != end_) { c = getNextChar(); if (c == '\\') getNextChar(); else if (c == '"') break; } return c == '"'; } bool Reader::readObject(Token &tokenStart) { Token tokenName; std::string name; currentValue() = Value(objectValue); currentValue().setOffsetStart(tokenStart.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) initialTokenOk = readToken(tokenName); if (!initialTokenOk) break; if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; name = ""; if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { Value numberName; if (!decodeNumber(tokenName, numberName)) return recoverFromError(tokenObjectEnd); name = numberName.asString(); } else { break; } Token colon; if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { return addErrorAndRecover( "Missing ':' after object member name", colon, tokenObjectEnd); } Value &value = currentValue()[name]; nodes_.push(&value); bool ok = readValue(); nodes_.pop(); if (!ok) // error already set return recoverFromError(tokenObjectEnd); Token comma; if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { return addErrorAndRecover( "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); } bool finalizeTokenOk = true; while (comma.type_ == tokenComment && finalizeTokenOk) finalizeTokenOk = readToken(comma); if (comma.type_ == tokenObjectEnd) return true; } return addErrorAndRecover( "Missing '}' or object member name", tokenName, tokenObjectEnd); } bool Reader::readArray(Token &tokenStart) { currentValue() = Value(arrayValue); currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); if (*current_ == ']') // empty array { Token endArray; readToken(endArray); return true; } int index = 0; for (;;) { Value &value = currentValue()[index++]; nodes_.push(&value); bool ok = readValue(); nodes_.pop(); if (!ok) // error already set return recoverFromError(tokenArrayEnd); Token token; // Accept Comment after last item in the array. ok = readToken(token); while (token.type_ == tokenComment && ok) { ok = readToken(token); } bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); if (!ok || badTokenType) { return addErrorAndRecover( "Missing ',' or ']' in array declaration", token, tokenArrayEnd); } if (token.type_ == tokenArrayEnd) break; } return true; } bool Reader::decodeNumber(Token &token) { Value decoded; if (!decodeNumber(token, decoded)) return false; currentValue() = decoded; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); return true; } bool Reader::decodeNumber(Token &token, Value &decoded) { bool isDouble = false; for (Location inspect = token.start_; inspect != token.end_; ++inspect) { isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') || (*inspect == '-' && inspect != token.start_); } if (isDouble) return decodeDouble(token, decoded); // Attempts to parse the number as an integer. If the number is // larger than the maximum supported value of an integer then // we decode the number as a double. Location current = token.start_; bool isNegative = *current == '-'; if (isNegative) ++current; Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) : Value::maxLargestUInt; Value::LargestUInt threshold = maxIntegerValue / 10; Value::LargestUInt value = 0; while (current < token.end_) { Char c = *current++; if (c < '0' || c > '9') return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); Value::UInt digit(c - '0'); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and // c) it's small enough to fit in that rounding delta, we're okay. // Otherwise treat this number as a double to avoid overflow. if (value > threshold || current != token.end_ || digit > maxIntegerValue % 10) { return decodeDouble(token, decoded); } } value = value * 10 + digit; } if (isNegative) decoded = -Value::LargestInt(value); else if (value <= Value::LargestUInt(Value::maxInt)) decoded = Value::LargestInt(value); else decoded = value; return true; } bool Reader::decodeDouble(Token &token) { Value decoded; if (!decodeDouble(token, decoded)) return false; currentValue() = decoded; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); return true; } bool Reader::decodeDouble(Token &token, Value &decoded) { double value = 0; const int bufferSize = 32; int count; int length = int(token.end_ - token.start_); // Sanity check to avoid buffer overflow exploits. if (length < 0) { return addError("Unable to parse token length", token); } // Avoid using a string constant for the format control string given to // sscanf, as this can cause hard to debug crashes on OS X. See here for more // info: // // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html char format[] = "%lf"; if (length <= bufferSize) { Char buffer[bufferSize + 1]; memcpy(buffer, token.start_, length); buffer[length] = 0; count = sscanf(buffer, format, &value); } else { std::string buffer(token.start_, token.end_); count = sscanf(buffer.c_str(), format, &value); } if (count != 1) return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); decoded = value; return true; } bool Reader::decodeString(Token &token) { std::string decoded; if (!decodeString(token, decoded)) return false; currentValue() = decoded; currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); return true; } bool Reader::decodeString(Token &token, std::string &decoded) { decoded.reserve(token.end_ - token.start_ - 2); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { Char c = *current++; if (c == '"') break; else if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); Char escape = *current++; switch (escape) { case '"': decoded += '"'; break; case '/': decoded += '/'; break; case '\\': decoded += '\\'; break; case 'b': decoded += '\b'; break; case 'f': decoded += '\f'; break; case 'n': decoded += '\n'; break; case 'r': decoded += '\r'; break; case 't': decoded += '\t'; break; case 'u': { unsigned int unicode; if (!decodeUnicodeCodePoint(token, current, end, unicode)) return false; decoded += codePointToUTF8(unicode); } break; default: return addError("Bad escape sequence in string", token, current); } } else { decoded += c; } } return true; } bool Reader::decodeUnicodeCodePoint(Token &token, Location ¤t, Location end, unsigned int &unicode) { if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) return false; if (unicode >= 0xD800 && unicode <= 0xDBFF) { // surrogate pairs if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", token, current); unsigned int surrogatePair; if (*(current++) == '\\' && *(current++) == 'u') { if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); } else return false; } else return addError("expecting another \\u token to begin the second half of " "a unicode surrogate pair", token, current); } return true; } bool Reader::decodeUnicodeEscapeSequence(Token &token, Location ¤t, Location end, unsigned int &unicode) { if (end - current < 4) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); unicode = 0; for (int index = 0; index < 4; ++index) { Char c = *current++; unicode *= 16; if (c >= '0' && c <= '9') unicode += c - '0'; else if (c >= 'a' && c <= 'f') unicode += c - 'a' + 10; else if (c >= 'A' && c <= 'F') unicode += c - 'A' + 10; else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current); } return true; } bool Reader::addError(const std::string &message, Token &token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; info.extra_ = extra; errors_.push_back(info); return false; } bool Reader::recoverFromError(TokenType skipUntilToken) { int errorCount = int(errors_.size()); Token skip; for (;;) { if (!readToken(skip)) errors_.resize(errorCount); // discard errors caused by recovery if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) break; } errors_.resize(errorCount); return false; } bool Reader::addErrorAndRecover(const std::string &message, Token &token, TokenType skipUntilToken) { addError(message, token); return recoverFromError(skipUntilToken); } Value &Reader::currentValue() { return *(nodes_.top()); } Reader::Char Reader::getNextChar() { if (current_ == end_) return 0; return *current_++; } void Reader::getLocationLineAndColumn(Location location, int &line, int &column) const { Location current = begin_; Location lastLineStart = current; line = 0; while (current < location && current != end_) { Char c = *current++; if (c == '\r') { if (*current == '\n') ++current; lastLineStart = current; ++line; } else if (c == '\n') { lastLineStart = current; ++line; } } // column & line start at 1 column = int(location - lastLineStart) + 1; ++line; } std::string Reader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) #if defined(WINCE) _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); #else sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); #endif #else snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); #endif return buffer; } // Deprecated. Preserved for backward compatibility std::string Reader::getFormatedErrorMessages() const { return getFormattedErrorMessages(); } std::string Reader::getFormattedErrorMessages() const { std::string formattedMessage; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { const ErrorInfo &error = *itError; formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; if (error.extra_) formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; } return formattedMessage; } std::vector Reader::getStructuredErrors() const { std::vector allErrors; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { const ErrorInfo &error = *itError; Reader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; structured.message = error.message_; allErrors.push_back(structured); } return allErrors; } std::istream &operator>>(std::istream &sin, Value &root) { Json::Reader reader; bool ok = reader.parse(sin, root, true); if (!ok) { fprintf(stderr, "Error from reader: %s", reader.getFormattedErrorMessages().c_str()); JSON_FAIL_MESSAGE("reader error"); } return sin; } } // namespace Json // vim: et ts=2 sts=2 sw=2 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_reader.cpp // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_batchallocator.h // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED #define JSONCPP_BATCHALLOCATOR_H_INCLUDED #include #include #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION namespace Json { /* Fast memory allocator. * * This memory allocator allocates memory for a batch of object (specified by * the page size, the number of object in each page). * * It does not allow the destruction of a single object. All the allocated * objects can be destroyed at once. The memory can be either released or reused * for future allocation. * * The in-place new operator must be used to construct the object using the * pointer returned by allocate. */ template class BatchAllocator { public: BatchAllocator(unsigned int objectsPerPage = 255) : freeHead_(0), objectsPerPage_(objectsPerPage) { // printf( "Size: %d => %s\n", sizeof(AllocatedType), // typeid(AllocatedType).name() ); assert(sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *)); // We must be able to store a slist in the // object free space. assert(objectsPerPage >= 16); batches_ = allocateBatch(0); // allocated a dummy page currentBatch_ = batches_; } ~BatchAllocator() { for (BatchInfo *batch = batches_; batch;) { BatchInfo *nextBatch = batch->next_; free(batch); batch = nextBatch; } } /// allocate space for an array of objectPerAllocation object. /// @warning it is the responsability of the caller to call objects /// constructors. AllocatedType *allocate() { if (freeHead_) // returns node from free list. { AllocatedType *object = freeHead_; freeHead_ = *(AllocatedType **)object; return object; } if (currentBatch_->used_ == currentBatch_->end_) { currentBatch_ = currentBatch_->next_; while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_) currentBatch_ = currentBatch_->next_; if (!currentBatch_) // no free batch found, allocate a new one { currentBatch_ = allocateBatch(objectsPerPage_); currentBatch_->next_ = batches_; // insert at the head of the list batches_ = currentBatch_; } } AllocatedType *allocated = currentBatch_->used_; currentBatch_->used_ += objectPerAllocation; return allocated; } /// Release the object. /// @warning it is the responsability of the caller to actually destruct the /// object. void release(AllocatedType *object) { assert(object != 0); *(AllocatedType **)object = freeHead_; freeHead_ = object; } private: struct BatchInfo { BatchInfo *next_; AllocatedType *used_; AllocatedType *end_; AllocatedType buffer_[objectPerAllocation]; }; // disabled copy constructor and assignement operator. BatchAllocator(const BatchAllocator &); void operator=(const BatchAllocator &); static BatchInfo *allocateBatch(unsigned int objectsPerPage) { const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; BatchInfo *batch = static_cast(malloc(mallocSize)); batch->next_ = 0; batch->used_ = batch->buffer_; batch->end_ = batch->buffer_ + objectsPerPage; return batch; } BatchInfo *batches_; BatchInfo *currentBatch_; /// Head of a single linked list within the allocated space of freeed object AllocatedType *freeHead_; unsigned int objectsPerPage_; }; } // namespace Json #endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED // vim: et ts=2 sts=2 sw=2 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_batchallocator.h // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // included by json_value.cpp namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIteratorBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIteratorBase::ValueIteratorBase() #ifndef JSON_VALUE_USE_INTERNAL_MAP : current_() , isNull_( true ) { } #else : isArray_( true ) , isNull_( true ) { iterator_.array_ = ValueInternalArray::IteratorState(); } #endif #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) : current_( current ) , isNull_( false ) { } #else ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) : isArray_( true ) { iterator_.array_ = state; } ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) : isArray_( false ) { iterator_.map_ = state; } #endif Value & ValueIteratorBase::deref() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP return current_->second; #else if ( isArray_ ) return ValueInternalArray::dereference( iterator_.array_ ); return ValueInternalMap::value( iterator_.map_ ); #endif } void ValueIteratorBase::increment() { #ifndef JSON_VALUE_USE_INTERNAL_MAP ++current_; #else if ( isArray_ ) ValueInternalArray::increment( iterator_.array_ ); ValueInternalMap::increment( iterator_.map_ ); #endif } void ValueIteratorBase::decrement() { #ifndef JSON_VALUE_USE_INTERNAL_MAP --current_; #else if ( isArray_ ) ValueInternalArray::decrement( iterator_.array_ ); ValueInternalMap::decrement( iterator_.map_ ); #endif } ValueIteratorBase::difference_type ValueIteratorBase::computeDistance( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP # ifdef JSON_USE_CPPTL_SMALLMAP return current_ - other.current_; # else // Iterator for null value are initialized using the default // constructor, which initialize current_ to the default // std::map::iterator. As begin() and end() are two instance // of the default std::map::iterator, they can not be compared. // To allow this, we handle this comparison specifically. if ( isNull_ && other.isNull_ ) { return 0; } // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, // which is the one used by default). // Using a portable hand-made version for non random iterator instead: // return difference_type( std::distance( current_, other.current_ ) ); difference_type myDistance = 0; for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) { ++myDistance; } return myDistance; # endif #else if ( isArray_ ) return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); #endif } bool ValueIteratorBase::isEqual( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP if ( isNull_ ) { return other.isNull_; } return current_ == other.current_; #else if ( isArray_ ) return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); #endif } void ValueIteratorBase::copy( const SelfType &other ) { #ifndef JSON_VALUE_USE_INTERNAL_MAP current_ = other.current_; isNull_ = other.isNull_; #else if ( isArray_ ) iterator_.array_ = other.iterator_.array_; iterator_.map_ = other.iterator_.map_; #endif } Value ValueIteratorBase::key() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( czstring.c_str() ) { if ( czstring.isStaticString() ) return Value( StaticString( czstring.c_str() ) ); return Value( czstring.c_str() ); } return Value( czstring.index() ); #else if ( isArray_ ) return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); bool isStatic; const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); if ( isStatic ) return Value( StaticString( memberName ) ); return Value( memberName ); #endif } UInt ValueIteratorBase::index() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( !czstring.c_str() ) return czstring.index(); return Value::UInt( -1 ); #else if ( isArray_ ) return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); return Value::UInt( -1 ); #endif } const char * ValueIteratorBase::memberName() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const char *name = (*current_).first.c_str(); return name ? name : ""; #else if ( !isArray_ ) return ValueInternalMap::key( iterator_.map_ ); return ""; #endif } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueConstIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueConstIterator::ValueConstIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueConstIterator & ValueConstIterator::operator =( const ValueIteratorBase &other ) { copy( other ); return *this; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIterator::ValueIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueIterator::ValueIterator( const ValueConstIterator &other ) : ValueIteratorBase( other ) { } ValueIterator::ValueIterator( const ValueIterator &other ) : ValueIteratorBase( other ) { } ValueIterator & ValueIterator::operator =( const SelfType &other ) { copy( other ); return *this; } } // namespace Json // vim: et ts=3 sts=3 sw=3 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// // Copyright 2011 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) #include #include #include #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #ifdef JSON_USE_CPPTL #include #endif #include // size_t #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { // This is a walkaround to avoid the static initialization of Value::null. // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of // 8 (instead of 4) as a bit of future-proofing. #if defined(__ARMEL__) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #else #define ALIGNAS(byte_alignment) #endif static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = {0}; const unsigned char& kNullRef = kNull[0]; const Value& Value::null = reinterpret_cast(kNullRef); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); const UInt Value::maxUInt = UInt(-1); #if defined(JSON_HAS_INT64) const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); const UInt64 Value::maxUInt64 = UInt64(-1); // The constant is hard-coded because some compiler have trouble // converting Value::maxUInt64 to a double correctly (AIX/xlC). // Assumes that UInt64 is a 64 bits integer. static const double maxUInt64AsDouble = 18446744073709551615.0; #endif // defined(JSON_HAS_INT64) const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); const LargestUInt Value::maxLargestUInt = LargestUInt(-1); /// Unknown size marker static const unsigned int unknown = (unsigned)-1; #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { return d >= min && d <= max; } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); } template static inline double integerToDouble(T value) { return static_cast(value); } template static inline bool InRange(double d, T min, U max) { return d >= integerToDouble(min) && d <= integerToDouble(max); } #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) /** Duplicates the specified string value. * @param value Pointer to the string to duplicate. Must be zero-terminated if * length is "unknown". * @param length Length of the value. if equals to unknown, then it will be * computed using strlen(value). * @return Pointer on the duplicate instance of string. */ static inline char *duplicateStringValue(const char *value, unsigned int length = unknown) { if (length == unknown) length = (unsigned int)strlen(value); // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. if (length >= (unsigned)Value::maxInt) length = Value::maxInt - 1; char *newString = static_cast(malloc(length + 1)); JSON_ASSERT_MESSAGE(newString != 0, "in Json::Value::duplicateStringValue(): " "Failed to allocate string value buffer"); memcpy(newString, value, length); newString[length] = 0; return newString; } /** Free the string duplicated by duplicateStringValue(). */ static inline void releaseStringValue(char *value) { if (value) free(value); } } // namespace Json // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ValueInternals... // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #if !defined(JSON_IS_AMALGAMATION) #ifdef JSON_VALUE_USE_INTERNAL_MAP #include "json_internalarray.inl" #include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP #include "json_valueiterator.inl" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CommentInfo // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// Value::CommentInfo::CommentInfo() : comment_(0) {} Value::CommentInfo::~CommentInfo() { if (comment_) releaseStringValue(comment_); } void Value::CommentInfo::setComment(const char *text) { if (comment_) releaseStringValue(comment_); JSON_ASSERT(text != 0); JSON_ASSERT_MESSAGE( text[0] == '\0' || text[0] == '/', "in Json::Value::setComment(): Comments must start with /"); // It seems that /**/ style comments are acceptable as well. comment_ = duplicateStringValue(text); } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CZString // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #ifndef JSON_VALUE_USE_INTERNAL_MAP // Notes: index_ indicates if the string was allocated when // a string is stored. Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} Value::CZString::CZString(const char *cstr, DuplicationPolicy allocate) : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr), index_(allocate) {} Value::CZString::CZString(const CZString &other) : cstr_(other.index_ != noDuplication && other.cstr_ != 0 ? duplicateStringValue(other.cstr_) : other.cstr_), index_(other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) {} Value::CZString::~CZString() { if (cstr_ && index_ == duplicate) releaseStringValue(const_cast(cstr_)); } void Value::CZString::swap(CZString &other) { std::swap(cstr_, other.cstr_); std::swap(index_, other.index_); } Value::CZString &Value::CZString::operator=(const CZString &other) { CZString temp(other); swap(temp); return *this; } bool Value::CZString::operator<(const CZString &other) const { if (cstr_) return strcmp(cstr_, other.cstr_) < 0; return index_ < other.index_; } bool Value::CZString::operator==(const CZString &other) const { if (cstr_) return strcmp(cstr_, other.cstr_) == 0; return index_ == other.index_; } ArrayIndex Value::CZString::index() const { return index_; } const char *Value::CZString::c_str() const { return cstr_; } bool Value::CZString::isStaticString() const { return index_ == noDuplication; } #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::Value // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// /*! \internal Default constructor initialization must be equivalent to: * memset( this, 0, sizeof(Value) ) * This optimization is used in ValueInternalMap fast allocator. */ Value::Value(ValueType type) : type_(type), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { switch (type) { case nullValue: break; case intValue: case uintValue: value_.int_ = 0; break; case realValue: value_.real_ = 0.0; break; case stringValue: value_.string_ = 0; break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArray(); break; case objectValue: value_.map_ = mapAllocator()->newMap(); break; #endif case booleanValue: value_.bool_ = false; break; default: JSON_ASSERT_UNREACHABLE; } } Value::Value(UInt value) : type_(uintValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.uint_ = value; } Value::Value(Int value) : type_(intValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.int_ = value; } #if defined(JSON_HAS_INT64) Value::Value(Int64 value) : type_(intValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.int_ = value; } Value::Value(UInt64 value) : type_(uintValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.uint_ = value; } #endif // defined(JSON_HAS_INT64) Value::Value(double value) : type_(realValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.real_ = value; } Value::Value(const char *value) : type_(stringValue), allocated_(true) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.string_ = duplicateStringValue(value); } Value::Value(const char *beginValue, const char *endValue) : type_(stringValue), allocated_(true) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.string_ = duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue)); } Value::Value(const std::string &value) : type_(stringValue), allocated_(true) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.string_ = duplicateStringValue(value.c_str(), (unsigned int)value.length()); } Value::Value(const StaticString &value) : type_(stringValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.string_ = const_cast(value.c_str()); } #ifdef JSON_USE_CPPTL Value::Value(const CppTL::ConstString &value) : type_(stringValue), allocated_(true) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.string_ = duplicateStringValue(value, value.length()); } #endif Value::Value(bool value) : type_(booleanValue), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(0), limit_(0) { value_.bool_ = value; } Value::Value(const Value &other) : type_(other.type_), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(other.start_), limit_(other.limit_) { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: value_ = other.value_; break; case stringValue: if (other.value_.string_) { value_.string_ = duplicateStringValue(other.value_.string_); allocated_ = true; } else { value_.string_ = 0; allocated_ = false; } break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(*other.value_.map_); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_); break; case objectValue: value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (other.comments_) { comments_ = new CommentInfo[numberOfCommentPlacement]; for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { const CommentInfo &otherComment = other.comments_[comment]; if (otherComment.comment_) comments_[comment].setComment(otherComment.comment_); } } } Value::~Value() { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: break; case stringValue: if (allocated_) releaseStringValue(value_.string_); break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: delete value_.map_; break; #else case arrayValue: arrayAllocator()->destructArray(value_.array_); break; case objectValue: mapAllocator()->destructMap(value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (comments_) delete[] comments_; } Value &Value::operator=(const Value &other) { Value temp(other); swap(temp); return *this; } void Value::swap(Value &other) { ValueType temp = type_; type_ = other.type_; other.type_ = temp; std::swap(value_, other.value_); int temp2 = allocated_; allocated_ = other.allocated_; other.allocated_ = temp2; std::swap(start_, other.start_); std::swap(limit_, other.limit_); } ValueType Value::type() const { return type_; } int Value::compare(const Value &other) const { if (*this < other) return -1; if (*this > other) return 1; return 0; } bool Value::operator<(const Value &other) const { int typeDelta = type_ - other.type_; if (typeDelta) return typeDelta < 0 ? true : false; switch (type_) { case nullValue: return false; case intValue: return value_.int_ < other.value_.int_; case uintValue: return value_.uint_ < other.value_.uint_; case realValue: return value_.real_ < other.value_.real_; case booleanValue: return value_.bool_ < other.value_.bool_; case stringValue: return (value_.string_ == 0 && other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) < 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: { int delta = int(value_.map_->size() - other.value_.map_->size()); if (delta) return delta < 0; return (*value_.map_) < (*other.value_.map_); } #else case arrayValue: return value_.array_->compare(*(other.value_.array_)) < 0; case objectValue: return value_.map_->compare(*(other.value_.map_)) < 0; #endif default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable } bool Value::operator<=(const Value &other) const { return !(other < *this); } bool Value::operator>=(const Value &other) const { return !(*this < other); } bool Value::operator>(const Value &other) const { return other < *this; } bool Value::operator==(const Value &other) const { // if ( type_ != other.type_ ) // GCC 2.95.3 says: // attempt to take address of bit-field structure member `Json::Value::type_' // Beats me, but a temp solves the problem. int temp = other.type_; if (type_ != temp) return false; switch (type_) { case nullValue: return true; case intValue: return value_.int_ == other.value_.int_; case uintValue: return value_.uint_ == other.value_.uint_; case realValue: return value_.real_ == other.value_.real_; case booleanValue: return value_.bool_ == other.value_.bool_; case stringValue: return (value_.string_ == other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) == 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); #else case arrayValue: return value_.array_->compare(*(other.value_.array_)) == 0; case objectValue: return value_.map_->compare(*(other.value_.map_)) == 0; #endif default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable } bool Value::operator!=(const Value &other) const { return !(*this == other); } const char *Value::asCString() const { JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue"); return value_.string_; } std::string Value::asString() const { switch (type_) { case nullValue: return ""; case stringValue: return value_.string_ ? value_.string_ : ""; case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: return valueToString(value_.int_); case uintValue: return valueToString(value_.uint_); case realValue: return valueToString(value_.real_); default: JSON_FAIL_MESSAGE("Type is not convertible to string"); } } #ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString() const { return CppTL::ConstString(asString().c_str()); } #endif Value::Int Value::asInt() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); return Int(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); return Int(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range"); return Int(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to Int."); } Value::UInt Value::asUInt() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); return UInt(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); return UInt(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range"); return UInt(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to UInt."); } #if defined(JSON_HAS_INT64) Value::Int64 Value::asInt64() const { switch (type_) { case intValue: return Int64(value_.int_); case uintValue: JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); return Int64(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range"); return Int64(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to Int64."); } Value::UInt64 Value::asUInt64() const { switch (type_) { case intValue: JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); return UInt64(value_.int_); case uintValue: return UInt64(value_.uint_); case realValue: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range"); return UInt64(value_.real_); case nullValue: return 0; case booleanValue: return value_.bool_ ? 1 : 0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); } #endif // if defined(JSON_HAS_INT64) LargestInt Value::asLargestInt() const { #if defined(JSON_NO_INT64) return asInt(); #else return asInt64(); #endif } LargestUInt Value::asLargestUInt() const { #if defined(JSON_NO_INT64) return asUInt(); #else return asUInt64(); #endif } double Value::asDouble() const { switch (type_) { case intValue: return static_cast(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return integerToDouble(value_.uint_); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return value_.real_; case nullValue: return 0.0; case booleanValue: return value_.bool_ ? 1.0 : 0.0; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to double."); } float Value::asFloat() const { switch (type_) { case intValue: return static_cast(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return integerToDouble(value_.uint_); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast(value_.real_); case nullValue: return 0.0; case booleanValue: return value_.bool_ ? 1.0f : 0.0f; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to float."); } bool Value::asBool() const { switch (type_) { case booleanValue: return value_.bool_; case nullValue: return false; case intValue: return value_.int_ ? true : false; case uintValue: return value_.uint_ ? true : false; case realValue: return value_.real_ ? true : false; default: break; } JSON_FAIL_MESSAGE("Value is not convertible to bool."); } bool Value::isConvertibleTo(ValueType other) const { switch (other) { case nullValue: return (isNumeric() && asDouble() == 0.0) || (type_ == booleanValue && value_.bool_ == false) || (type_ == stringValue && asString() == "") || (type_ == arrayValue && value_.map_->size() == 0) || (type_ == objectValue && value_.map_->size() == 0) || type_ == nullValue; case intValue: return isInt() || (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || type_ == booleanValue || type_ == nullValue; case uintValue: return isUInt() || (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || type_ == booleanValue || type_ == nullValue; case realValue: return isNumeric() || type_ == booleanValue || type_ == nullValue; case booleanValue: return isNumeric() || type_ == booleanValue || type_ == nullValue; case stringValue: return isNumeric() || type_ == booleanValue || type_ == stringValue || type_ == nullValue; case arrayValue: return type_ == arrayValue || type_ == nullValue; case objectValue: return type_ == objectValue || type_ == nullValue; } JSON_ASSERT_UNREACHABLE; return false; } /// Number of values in array or object ArrayIndex Value::size() const { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: case stringValue: return 0; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: // size of the array is highest index + 1 if (!value_.map_->empty()) { ObjectValues::const_iterator itLast = value_.map_->end(); --itLast; return (*itLast).first.index() + 1; } return 0; case objectValue: return ArrayIndex(value_.map_->size()); #else case arrayValue: return Int(value_.array_->size()); case objectValue: return Int(value_.map_->size()); #endif } JSON_ASSERT_UNREACHABLE; return 0; // unreachable; } bool Value::empty() const { if (isNull() || isArray() || isObject()) return size() == 0u; else return false; } bool Value::operator!() const { return isNull(); } void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value"); start_ = 0; limit_ = 0; switch (type_) { #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_->clear(); break; #else case arrayValue: value_.array_->clear(); break; case objectValue: value_.map_->clear(); break; #endif default: break; } } void Value::resize(ArrayIndex newSize) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, "in Json::Value::resize(): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP ArrayIndex oldSize = size(); if (newSize == 0) clear(); else if (newSize > oldSize) (*this)[newSize - 1]; else { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); } assert(size() == newSize); } #else value_.array_->resize(newSize); #endif } Value &Value::operator[](ArrayIndex index) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::iterator it = value_.map_->lower_bound(key); if (it != value_.map_->end() && (*it).first == key) return (*it).second; ObjectValues::value_type defaultValue(key, null); it = value_.map_->insert(it, defaultValue); return (*it).second; #else return value_.array_->resolveReference(index); #endif } Value &Value::operator[](int index) { JSON_ASSERT_MESSAGE( index >= 0, "in Json::Value::operator[](int index): index cannot be negative"); return (*this)[ArrayIndex(index)]; } const Value &Value::operator[](ArrayIndex index) const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) return null; return (*it).second; #else Value *value = value_.array_->find(index); return value ? *value : null; #endif } const Value &Value::operator[](int index) const { JSON_ASSERT_MESSAGE( index >= 0, "in Json::Value::operator[](int index) const: index cannot be negative"); return (*this)[ArrayIndex(index)]; } Value &Value::operator[](const char *key) { return resolveReference(key, false); } Value &Value::resolveReference(const char *key, bool isStatic) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::resolveReference(): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; ObjectValues::value_type defaultValue(actualKey, null); it = value_.map_->insert(it, defaultValue); Value &value = (*it).second; return value; #else return value_.map_->resolveReference(key, isStatic); #endif } Value Value::get(ArrayIndex index, const Value &defaultValue) const { const Value *value = &((*this)[index]); return value == &null ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } const Value &Value::operator[](const char *key) const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::operator[](char const*)const: requires objectValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey(key, CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return null; return (*it).second; #else const Value *value = value_.map_->find(key); return value ? *value : null; #endif } Value &Value::operator[](const std::string &key) { return (*this)[key.c_str()]; } const Value &Value::operator[](const std::string &key) const { return (*this)[key.c_str()]; } Value &Value::operator[](const StaticString &key) { return resolveReference(key, true); } #ifdef JSON_USE_CPPTL Value &Value::operator[](const CppTL::ConstString &key) { return (*this)[key.c_str()]; } const Value &Value::operator[](const CppTL::ConstString &key) const { return (*this)[key.c_str()]; } #endif Value &Value::append(const Value &value) { return (*this)[size()] = value; } Value Value::get(const char *key, const Value &defaultValue) const { const Value *value = &((*this)[key]); return value == &null ? defaultValue : *value; } Value Value::get(const std::string &key, const Value &defaultValue) const { return get(key.c_str(), defaultValue); } Value Value::removeMember(const char *key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey(key, CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return null; Value old(it->second); value_.map_->erase(it); return old; #else Value *value = value_.map_->find(key); if (value) { Value old(*value); value_.map_.remove(key); return old; } else { return null; } #endif } Value Value::removeMember(const std::string &key) { return removeMember(key.c_str()); } #ifdef JSON_USE_CPPTL Value Value::get(const CppTL::ConstString &key, const Value &defaultValue) const { return get(key.c_str(), defaultValue); } #endif bool Value::isMember(const char *key) const { const Value *value = &((*this)[key]); return value != &null; } bool Value::isMember(const std::string &key) const { return isMember(key.c_str()); } #ifdef JSON_USE_CPPTL bool Value::isMember(const CppTL::ConstString &key) const { return isMember(key.c_str()); } #endif Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::getMemberNames(), value must be objectValue"); if (type_ == nullValue) return Value::Members(); Members members; members.reserve(value_.map_->size()); #ifndef JSON_VALUE_USE_INTERNAL_MAP ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) members.push_back(std::string((*it).first.c_str())); #else ValueInternalMap::IteratorState it; ValueInternalMap::IteratorState itEnd; value_.map_->makeBeginIterator(it); value_.map_->makeEndIterator(itEnd); for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it)) members.push_back(std::string(ValueInternalMap::key(it))); #endif return members; } // //# ifdef JSON_USE_CPPTL // EnumMemberNames // Value::enumMemberNames() const //{ // if ( type_ == objectValue ) // { // return CppTL::Enum::any( CppTL::Enum::transform( // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), // MemberNamesTransform() ) ); // } // return EnumMemberNames(); //} // // // EnumValues // Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), // CppTL::Type() ); // return EnumValues(); //} // //# endif static bool IsIntegral(double d) { double integral_part; return modf(d, &integral_part) == 0.0; } bool Value::isNull() const { return type_ == nullValue; } bool Value::isBool() const { return type_ == booleanValue; } bool Value::isInt() const { switch (type_) { case intValue: return value_.int_ >= minInt && value_.int_ <= maxInt; case uintValue: return value_.uint_ <= UInt(maxInt); case realValue: return value_.real_ >= minInt && value_.real_ <= maxInt && IsIntegral(value_.real_); default: break; } return false; } bool Value::isUInt() const { switch (type_) { case intValue: return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); case uintValue: return value_.uint_ <= maxUInt; case realValue: return value_.real_ >= 0 && value_.real_ <= maxUInt && IsIntegral(value_.real_); default: break; } return false; } bool Value::isInt64() const { #if defined(JSON_HAS_INT64) switch (type_) { case intValue: return true; case uintValue: return value_.uint_ <= UInt64(maxInt64); case realValue: // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a // double, so double(maxInt64) will be rounded up to 2^63. Therefore we // require the value to be strictly less than the limit. return value_.real_ >= double(minInt64) && value_.real_ < double(maxInt64) && IsIntegral(value_.real_); default: break; } #endif // JSON_HAS_INT64 return false; } bool Value::isUInt64() const { #if defined(JSON_HAS_INT64) switch (type_) { case intValue: return value_.int_ >= 0; case uintValue: return true; case realValue: // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we // require the value to be strictly less than the limit. return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); default: break; } #endif // JSON_HAS_INT64 return false; } bool Value::isIntegral() const { #if defined(JSON_HAS_INT64) return isInt64() || isUInt64(); #else return isInt() || isUInt(); #endif } bool Value::isDouble() const { return type_ == realValue || isIntegral(); } bool Value::isNumeric() const { return isIntegral() || isDouble(); } bool Value::isString() const { return type_ == stringValue; } bool Value::isArray() const { return type_ == arrayValue; } bool Value::isObject() const { return type_ == objectValue; } void Value::setComment(const char *comment, CommentPlacement placement) { if (!comments_) comments_ = new CommentInfo[numberOfCommentPlacement]; comments_[placement].setComment(comment); } void Value::setComment(const std::string &comment, CommentPlacement placement) { setComment(comment.c_str(), placement); } bool Value::hasComment(CommentPlacement placement) const { return comments_ != 0 && comments_[placement].comment_ != 0; } std::string Value::getComment(CommentPlacement placement) const { if (hasComment(placement)) return comments_[placement].comment_; return ""; } void Value::setOffsetStart(size_t start) { start_ = start; } void Value::setOffsetLimit(size_t limit) { limit_ = limit; } size_t Value::getOffsetStart() const { return start_; } size_t Value::getOffsetLimit() const { return limit_; } std::string Value::toStyledString() const { StyledWriter writer; return writer.write(*this); } Value::const_iterator Value::begin() const { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->begin()); break; #endif default: break; } return const_iterator(); } Value::const_iterator Value::end() const { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->end()); break; #endif default: break; } return const_iterator(); } Value::iterator Value::begin() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->begin()); break; #endif default: break; } return iterator(); } Value::iterator Value::end() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->end()); break; #endif default: break; } return iterator(); } // class PathArgument // ////////////////////////////////////////////////////////////////// PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} PathArgument::PathArgument(ArrayIndex index) : key_(), index_(index), kind_(kindIndex) {} PathArgument::PathArgument(const char *key) : key_(key), index_(), kind_(kindKey) {} PathArgument::PathArgument(const std::string &key) : key_(key.c_str()), index_(), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// Path::Path(const std::string &path, const PathArgument &a1, const PathArgument &a2, const PathArgument &a3, const PathArgument &a4, const PathArgument &a5) { InArgs in; in.push_back(&a1); in.push_back(&a2); in.push_back(&a3); in.push_back(&a4); in.push_back(&a5); makePath(path, in); } void Path::makePath(const std::string &path, const InArgs &in) { const char *current = path.c_str(); const char *end = current + path.length(); InArgs::const_iterator itInArg = in.begin(); while (current != end) { if (*current == '[') { ++current; if (*current == '%') addPathInArg(path, in, itInArg, PathArgument::kindIndex); else { ArrayIndex index = 0; for (; current != end && *current >= '0' && *current <= '9'; ++current) index = index * 10 + ArrayIndex(*current - '0'); args_.push_back(index); } if (current == end || *current++ != ']') invalidPath(path, int(current - path.c_str())); } else if (*current == '%') { addPathInArg(path, in, itInArg, PathArgument::kindKey); ++current; } else if (*current == '.') { ++current; } else { const char *beginName = current; while (current != end && !strchr("[.", *current)) ++current; args_.push_back(std::string(beginName, current)); } } } void Path::addPathInArg(const std::string & /*path*/, const InArgs &in, InArgs::const_iterator &itInArg, PathArgument::Kind kind) { if (itInArg == in.end()) { // Error: missing argument %d } else if ((*itInArg)->kind_ != kind) { // Error: bad argument type } else { args_.push_back(**itInArg); } } void Path::invalidPath(const std::string & /*path*/, int /*location*/) { // Error: invalid path. } const Value &Path::resolve(const Value &root) const { const Value *node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument &arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // Error: unable to resolve path (array value expected at position... } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); if (node == &Value::null) { // Error: unable to resolve path (object has no member named '' at // position...) } } } return *node; } Value Path::resolve(const Value &root, const Value &defaultValue) const { const Value *node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument &arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) return defaultValue; node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); if (node == &Value::null) return defaultValue; } } return *node; } Value &Path::make(Value &root) const { Value *node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument &arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray()) { // Error: node is not an array at position ... } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: node is not an object at position... } node = &((*node)[arg.key_]); } } return *node; } } // namespace Json // vim: et ts=2 sts=2 sw=2 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////// // Beginning of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// // Copyright 2011 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) #include #include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif namespace Json { static bool containsControlCharacter(const char *str) { while (*str) { if (isControlCharacter(*(str++))) return true; } return false; } std::string valueToString(LargestInt value) { UIntToStringBuffer buffer; char *current = buffer + sizeof(buffer); bool isNegative = value < 0; if (isNegative) value = -value; uintToString(LargestUInt(value), current); if (isNegative) *--current = '-'; assert(current >= buffer); return current; } std::string valueToString(LargestUInt value) { UIntToStringBuffer buffer; char *current = buffer + sizeof(buffer); uintToString(value, current); assert(current >= buffer); return current; } #if defined(JSON_HAS_INT64) std::string valueToString(Int value) { return valueToString(LargestInt(value)); } std::string valueToString(UInt value) { return valueToString(LargestUInt(value)); } #endif // # if defined(JSON_HAS_INT64) std::string valueToString(double value) { // Allocate a buffer that is more than large enough to store the 16 digits of // precision requested below. char buffer[32]; // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distingish the // concepts of reals and integers. #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with // visual studio 2005 to // avoid warning. #if defined(WINCE) _snprintf(buffer, sizeof(buffer), "%.16g", value); #else sprintf_s(buffer, sizeof(buffer), "%.16g", value); #endif #else if ( isfinite( value )) { snprintf(buffer, sizeof(buffer), "%.16g", value); } else { // IEEE standard states that NaN values will not compare to themselves if ( value != value) { snprintf(buffer, sizeof(buffer), "null"); } else if ( value < 0) { snprintf(buffer, sizeof(buffer), "-1e+9999"); } else { snprintf(buffer, sizeof(buffer), "1e+9999"); } // nothing more to do, return. return buffer; } #endif fixNumericLocale(buffer, buffer + strlen(buffer)); return buffer; } std::string valueToString(bool value) { return value ? "true" : "false"; } std::string valueToQuotedString(const char *value) { if (value == NULL) return ""; // Not sure how to handle unicode... if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter(value)) return std::string("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to std::string is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) std::string::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL std::string result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; for (const char *c = value; *c != 0; ++c) { switch (*c) { case '\"': result += "\\\""; break; case '\\': result += "\\\\"; break; case '\b': result += "\\b"; break; case '\f': result += "\\f"; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; // case '/': // Even though \/ is considered a legal escape in JSON, a bare // slash is also legal, so I see no reason to escape it. // (I hope I am not misunderstanding something. // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); result += oss.str(); } else { result += *c; } break; } } result += "\""; return result; } // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false) {} void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } std::string FastWriter::write(const Value &root) { document_ = ""; writeValue(root); document_ += "\n"; return document_; } void FastWriter::writeValue(const Value &value) { switch (value.type()) { case nullValue: if (!dropNullPlaceholders_) document_ += "null"; break; case intValue: document_ += valueToString(value.asLargestInt()); break; case uintValue: document_ += valueToString(value.asLargestUInt()); break; case realValue: document_ += valueToString(value.asDouble()); break; case stringValue: document_ += valueToQuotedString(value.asCString()); break; case booleanValue: document_ += valueToString(value.asBool()); break; case arrayValue: { document_ += "["; int size = value.size(); for (int index = 0; index < size; ++index) { if (index > 0) document_ += ","; writeValue(value[index]); } document_ += "]"; } break; case objectValue: { Value::Members members(value.getMemberNames()); document_ += "{"; for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { const std::string &name = *it; if (it != members.begin()) document_ += ","; document_ += valueToQuotedString(name.c_str()); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue(value[name]); } document_ += "}"; } break; } } // Class StyledWriter // ////////////////////////////////////////////////////////////////// StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} std::string StyledWriter::write(const Value &root) { document_ = ""; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); document_ += "\n"; return document_; } void StyledWriter::writeValue(const Value &value) { switch (value.type()) { case nullValue: pushValue("null"); break; case intValue: pushValue(valueToString(value.asLargestInt())); break; case uintValue: pushValue(valueToString(value.asLargestUInt())); break; case realValue: pushValue(valueToString(value.asDouble())); break; case stringValue: pushValue(valueToQuotedString(value.asCString())); break; case booleanValue: pushValue(valueToString(value.asBool())); break; case arrayValue: writeArrayValue(value); break; case objectValue: { Value::Members members(value.getMemberNames()); if (members.empty()) pushValue("{}"); else { writeWithIndent("{"); indent(); Value::Members::iterator it = members.begin(); for (;;) { const std::string &name = *it; const Value &childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); document_ += " : "; writeValue(childValue); if (++it == members.end()) { writeCommentAfterValueOnSameLine(childValue); break; } document_ += ","; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("}"); } } break; } } void StyledWriter::writeArrayValue(const Value &value) { unsigned size = value.size(); if (size == 0) pushValue("[]"); else { bool isArrayMultiLine = isMultineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); bool hasChildValue = !childValues_.empty(); unsigned index = 0; for (;;) { const Value &childValue = value[index]; writeCommentBeforeValue(childValue); if (hasChildValue) writeWithIndent(childValues_[index]); else { writeIndent(); writeValue(childValue); } if (++index == size) { writeCommentAfterValueOnSameLine(childValue); break; } document_ += ","; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("]"); } else // output on a single line { assert(childValues_.size() == size); document_ += "[ "; for (unsigned index = 0; index < size; ++index) { if (index > 0) document_ += ", "; document_ += childValues_[index]; } document_ += " ]"; } } } bool StyledWriter::isMultineArray(const Value &value) { int size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (int index = 0; index < size && !isMultiLine; ++index) { const Value &childValue = value[index]; isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' for (int index = 0; index < size; ++index) { writeValue(value[index]); lineLength += int(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; } return isMultiLine; } void StyledWriter::pushValue(const std::string &value) { if (addChildValues_) childValues_.push_back(value); else document_ += value; } void StyledWriter::writeIndent() { if (!document_.empty()) { char last = document_[document_.length() - 1]; if (last == ' ') // already indented return; if (last != '\n') // Comments may add new-line document_ += '\n'; } document_ += indentString_; } void StyledWriter::writeWithIndent(const std::string &value) { writeIndent(); document_ += value; } void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } void StyledWriter::unindent() { assert(int(indentString_.size()) >= indentSize_); indentString_.resize(indentString_.size() - indentSize_); } void StyledWriter::writeCommentBeforeValue(const Value &root) { if (!root.hasComment(commentBefore)) return; document_ += "\n"; writeIndent(); std::string normalizedComment = normalizeEOL(root.getComment(commentBefore)); std::string::const_iterator iter = normalizedComment.begin(); while (iter != normalizedComment.end()) { document_ += *iter; if (*iter == '\n' && *(iter + 1) == '/') writeIndent(); ++iter; } // Comments are stripped of newlines, so add one here document_ += "\n"; } void StyledWriter::writeCommentAfterValueOnSameLine(const Value &root) { if (root.hasComment(commentAfterOnSameLine)) document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); if (root.hasComment(commentAfter)) { document_ += "\n"; document_ += normalizeEOL(root.getComment(commentAfter)); document_ += "\n"; } } bool StyledWriter::hasCommentForValue(const Value &value) { return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter); } std::string StyledWriter::normalizeEOL(const std::string &text) { std::string normalized; normalized.reserve(text.length()); const char *begin = text.c_str(); const char *end = begin + text.length(); const char *current = begin; while (current != end) { char c = *current++; if (c == '\r') // mac or dos EOL { if (*current == '\n') // convert dos EOL ++current; normalized += '\n'; } else // handle unix EOL & other char normalized += c; } return normalized; } // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// StyledStreamWriter::StyledStreamWriter(std::string indentation) : document_(NULL), rightMargin_(74), indentation_(indentation), addChildValues_() {} void StyledStreamWriter::write(std::ostream &out, const Value &root) { document_ = &out; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); *document_ << "\n"; document_ = NULL; // Forget the stream, for safety. } void StyledStreamWriter::writeValue(const Value &value) { switch (value.type()) { case nullValue: pushValue("null"); break; case intValue: pushValue(valueToString(value.asLargestInt())); break; case uintValue: pushValue(valueToString(value.asLargestUInt())); break; case realValue: pushValue(valueToString(value.asDouble())); break; case stringValue: pushValue(valueToQuotedString(value.asCString())); break; case booleanValue: pushValue(valueToString(value.asBool())); break; case arrayValue: writeArrayValue(value); break; case objectValue: { Value::Members members(value.getMemberNames()); if (members.empty()) pushValue("{}"); else { writeWithIndent("{"); indent(); Value::Members::iterator it = members.begin(); for (;;) { const std::string &name = *it; const Value &childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); *document_ << " : "; writeValue(childValue); if (++it == members.end()) { writeCommentAfterValueOnSameLine(childValue); break; } *document_ << ","; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("}"); } } break; } } void StyledStreamWriter::writeArrayValue(const Value &value) { unsigned size = value.size(); if (size == 0) pushValue("[]"); else { bool isArrayMultiLine = isMultineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); bool hasChildValue = !childValues_.empty(); unsigned index = 0; for (;;) { const Value &childValue = value[index]; writeCommentBeforeValue(childValue); if (hasChildValue) writeWithIndent(childValues_[index]); else { writeIndent(); writeValue(childValue); } if (++index == size) { writeCommentAfterValueOnSameLine(childValue); break; } *document_ << ","; writeCommentAfterValueOnSameLine(childValue); } unindent(); writeWithIndent("]"); } else // output on a single line { assert(childValues_.size() == size); *document_ << "[ "; for (unsigned index = 0; index < size; ++index) { if (index > 0) *document_ << ", "; *document_ << childValues_[index]; } *document_ << " ]"; } } } bool StyledStreamWriter::isMultineArray(const Value &value) { int size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (int index = 0; index < size && !isMultiLine; ++index) { const Value &childValue = value[index]; isMultiLine = isMultiLine || ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' for (int index = 0; index < size; ++index) { writeValue(value[index]); lineLength += int(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; } return isMultiLine; } void StyledStreamWriter::pushValue(const std::string &value) { if (addChildValues_) childValues_.push_back(value); else *document_ << value; } void StyledStreamWriter::writeIndent() { /* Some comments in this method would have been nice. ;-) if ( !document_.empty() ) { char last = document_[document_.length()-1]; if ( last == ' ' ) // already indented return; if ( last != '\n' ) // Comments may add new-line *document_ << '\n'; } */ *document_ << '\n' << indentString_; } void StyledStreamWriter::writeWithIndent(const std::string &value) { writeIndent(); *document_ << value; } void StyledStreamWriter::indent() { indentString_ += indentation_; } void StyledStreamWriter::unindent() { assert(indentString_.size() >= indentation_.size()); indentString_.resize(indentString_.size() - indentation_.size()); } void StyledStreamWriter::writeCommentBeforeValue(const Value &root) { if (!root.hasComment(commentBefore)) return; *document_ << normalizeEOL(root.getComment(commentBefore)); *document_ << "\n"; } void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value &root) { if (root.hasComment(commentAfterOnSameLine)) *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine)); if (root.hasComment(commentAfter)) { *document_ << "\n"; *document_ << normalizeEOL(root.getComment(commentAfter)); *document_ << "\n"; } } bool StyledStreamWriter::hasCommentForValue(const Value &value) { return value.hasComment(commentBefore) || value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter); } std::string StyledStreamWriter::normalizeEOL(const std::string &text) { std::string normalized; normalized.reserve(text.length()); const char *begin = text.c_str(); const char *end = begin + text.length(); const char *current = begin; while (current != end) { char c = *current++; if (c == '\r') // mac or dos EOL { if (*current == '\n') // convert dos EOL ++current; normalized += '\n'; } else // handle unix EOL & other char normalized += c; } return normalized; } std::ostream &operator<<(std::ostream &sout, const Value &root) { Json::StyledStreamWriter writer; writer.write(sout, root); return sout; } } // namespace Json // vim: et ts=2 sts=2 sw=2 tw=0 // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// mongo-cxx-driver-legacy-1.1.2/src/third_party/murmurhash3/000077500000000000000000000000001273231111400235565ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/murmurhash3/MurmurHash3.cpp000066400000000000000000000177171273231111400264550ustar00rootroot00000000000000//----------------------------------------------------------------------------- // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. // Note - The x86 and x64 versions do _not_ produce the same results, as the // algorithms are optimized for their respective platforms. You can still // compile and run any of them on any platform, but your performance with the // non-native version will be less than optimal. #include "MurmurHash3.h" //----------------------------------------------------------------------------- // Platform-specific functions and macros // Microsoft Visual Studio #if defined(_MSC_VER) #define FORCE_INLINE __forceinline #include #define ROTL32(x,y) _rotl(x,y) #define ROTL64(x,y) _rotl64(x,y) #define BIG_CONSTANT(x) (x) // Other compilers #else // defined(_MSC_VER) #define FORCE_INLINE __attribute__((always_inline)) inline uint32_t rotl32 ( uint32_t x, int8_t r ) { return (x << r) | (x >> (32 - r)); } inline uint64_t rotl64 ( uint64_t x, int8_t r ) { return (x << r) | (x >> (64 - r)); } #define ROTL32(x,y) rotl32(x,y) #define ROTL64(x,y) rotl64(x,y) #define BIG_CONSTANT(x) (x##LLU) #endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here inline FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i ) { return p[i]; } inline FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i ) { return p[i]; } //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche inline FORCE_INLINE uint32_t fmix ( uint32_t h ) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } //---------- inline FORCE_INLINE uint64_t fmix ( uint64_t k ) { k ^= k >> 33; k *= BIG_CONSTANT(0xff51afd7ed558ccd); k ^= k >> 33; k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); k ^= k >> 33; return k; } //----------------------------------------------------------------------------- void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ) { const uint8_t * data = (const uint8_t*)key; const int nblocks = len / 4; uint32_t h1 = seed; uint32_t c1 = 0xcc9e2d51; uint32_t c2 = 0x1b873593; //---------- // body const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); for(int i = -nblocks; i; i++) { uint32_t k1 = getblock(blocks,i); k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1,13); h1 = h1*5+0xe6546b64; } //---------- // tail const uint8_t * tail = (const uint8_t*)(data + nblocks*4); uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h1 = fmix(h1); *(uint32_t*)out = h1; } //----------------------------------------------------------------------------- void MurmurHash3_x86_128 ( const void * key, const int len, uint32_t seed, void * out ) { const uint8_t * data = (const uint8_t*)key; const int nblocks = len / 16; uint32_t h1 = seed; uint32_t h2 = seed; uint32_t h3 = seed; uint32_t h4 = seed; uint32_t c1 = 0x239b961b; uint32_t c2 = 0xab0e9789; uint32_t c3 = 0x38b34ae5; uint32_t c4 = 0xa1e38b93; //---------- // body const uint32_t * blocks = (const uint32_t *)(data + nblocks*16); for(int i = -nblocks; i; i++) { uint32_t k1 = getblock(blocks,i*4+0); uint32_t k2 = getblock(blocks,i*4+1); uint32_t k3 = getblock(blocks,i*4+2); uint32_t k4 = getblock(blocks,i*4+3); k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; } //---------- // tail const uint8_t * tail = (const uint8_t*)(data + nblocks*16); uint32_t k1 = 0; uint32_t k2 = 0; uint32_t k3 = 0; uint32_t k4 = 0; switch(len & 15) { case 15: k4 ^= tail[14] << 16; case 14: k4 ^= tail[13] << 8; case 13: k4 ^= tail[12] << 0; k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; case 12: k3 ^= tail[11] << 24; case 11: k3 ^= tail[10] << 16; case 10: k3 ^= tail[ 9] << 8; case 9: k3 ^= tail[ 8] << 0; k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; case 8: k2 ^= tail[ 7] << 24; case 7: k2 ^= tail[ 6] << 16; case 6: k2 ^= tail[ 5] << 8; case 5: k2 ^= tail[ 4] << 0; k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; case 4: k1 ^= tail[ 3] << 24; case 3: k1 ^= tail[ 2] << 16; case 2: k1 ^= tail[ 1] << 8; case 1: k1 ^= tail[ 0] << 0; k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; h1 = fmix(h1); h2 = fmix(h2); h3 = fmix(h3); h4 = fmix(h4); h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; ((uint32_t*)out)[0] = h1; ((uint32_t*)out)[1] = h2; ((uint32_t*)out)[2] = h3; ((uint32_t*)out)[3] = h4; } //----------------------------------------------------------------------------- void MurmurHash3_x64_128 ( const void * key, const int len, const uint32_t seed, void * out ) { const uint8_t * data = (const uint8_t*)key; const int nblocks = len / 16; uint64_t h1 = seed; uint64_t h2 = seed; uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); //---------- // body const uint64_t * blocks = (const uint64_t *)(data); for(int i = 0; i < nblocks; i++) { uint64_t k1 = getblock(blocks,i*2+0); uint64_t k2 = getblock(blocks,i*2+1); k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; } //---------- // tail const uint8_t * tail = (const uint8_t*)(data + nblocks*16); uint64_t k1 = 0; uint64_t k2 = 0; switch(len & 15) { case 15: k2 ^= uint64_t(tail[14]) << 48; case 14: k2 ^= uint64_t(tail[13]) << 40; case 13: k2 ^= uint64_t(tail[12]) << 32; case 12: k2 ^= uint64_t(tail[11]) << 24; case 11: k2 ^= uint64_t(tail[10]) << 16; case 10: k2 ^= uint64_t(tail[ 9]) << 8; case 9: k2 ^= uint64_t(tail[ 8]) << 0; k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; case 8: k1 ^= uint64_t(tail[ 7]) << 56; case 7: k1 ^= uint64_t(tail[ 6]) << 48; case 6: k1 ^= uint64_t(tail[ 5]) << 40; case 5: k1 ^= uint64_t(tail[ 4]) << 32; case 4: k1 ^= uint64_t(tail[ 3]) << 24; case 3: k1 ^= uint64_t(tail[ 2]) << 16; case 2: k1 ^= uint64_t(tail[ 1]) << 8; case 1: k1 ^= uint64_t(tail[ 0]) << 0; k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h1 += h2; h2 += h1; h1 = fmix(h1); h2 = fmix(h2); h1 += h2; h2 += h1; ((uint64_t*)out)[0] = h1; ((uint64_t*)out)[1] = h2; } //----------------------------------------------------------------------------- mongo-cxx-driver-legacy-1.1.2/src/third_party/murmurhash3/MurmurHash3.h000066400000000000000000000013631273231111400261100ustar00rootroot00000000000000//----------------------------------------------------------------------------- // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. #ifndef _MURMURHASH3_H_ #define _MURMURHASH3_H_ #include //----------------------------------------------------------------------------- void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ); void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); //----------------------------------------------------------------------------- #endif // _MURMURHASH3_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/restclient/000077500000000000000000000000001273231111400234545ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/restclient/LICENSE000066400000000000000000000020461273231111400244630ustar00rootroot00000000000000Copyright (c) 2010 Daniel Schauenberg 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. mongo-cxx-driver-legacy-1.1.2/src/third_party/restclient/restclient.cpp000066400000000000000000000263701273231111400263440ustar00rootroot00000000000000/** * @file restclient.cpp * @brief implementation of the restclient class * @author Daniel Schauenberg */ /*======================== INCLUDES ========================*/ #include "restclient.h" #include #include #include #include /** initialize user agent string */ const char* RestClient::user_agent = "restclient-cpp/mongo-cxx-driver"; /** initialize authentication variable */ std::string RestClient::user_pass = std::string(); /** Authentication Methods implementation */ void RestClient::clearAuth(){ RestClient::user_pass.clear(); } void RestClient::setAuth(const std::string& user,const std::string& password){ RestClient::user_pass.clear(); RestClient::user_pass += user+":"+password; } /** * @brief HTTP GET method * * @param url to query * * @return response struct */ RestClient::response RestClient::get(const std::string& url) { /** create return struct */ RestClient::response ret = {}; // use libcurl CURL *curl = NULL; CURLcode res = CURLE_OK; curl = curl_easy_init(); if (curl) { /** set basic authentication if present*/ if(RestClient::user_pass.length()>0){ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_USERPWD, RestClient::user_pass.c_str()); } /** set user agent */ curl_easy_setopt(curl, CURLOPT_USERAGENT, RestClient::user_agent); /** set query URL */ curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); /** set callback function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RestClient::write_callback); /** set data object to pass to callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); /** set the header callback function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, RestClient::header_callback); /** callback object for headers */ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &ret); /** perform the actual query */ res = curl_easy_perform(curl); if (res != CURLE_OK) { ret.body = "Failed to query."; ret.code = -1; return ret; } long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); ret.code = static_cast(http_code); curl_easy_cleanup(curl); curl_global_cleanup(); } return ret; } /** * @brief HTTP POST method * * @param url to query * @param ctype content type as string * @param data HTTP POST body * * @return response struct */ RestClient::response RestClient::post(const std::string& url, const std::string& ctype, const std::string& data) { /** create return struct */ RestClient::response ret = {}; /** build content-type header string */ std::string ctype_header = "Content-Type: " + ctype; // use libcurl CURL *curl = NULL; CURLcode res = CURLE_OK; curl = curl_easy_init(); if (curl) { /** set basic authentication if present*/ if(RestClient::user_pass.length()>0){ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_USERPWD, RestClient::user_pass.c_str()); } /** set user agent */ curl_easy_setopt(curl, CURLOPT_USERAGENT, RestClient::user_agent); /** set query URL */ curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); /** Now specify we want to POST data */ curl_easy_setopt(curl, CURLOPT_POST, 1L); /** set post fields */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size()); /** set callback function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RestClient::write_callback); /** set data object to pass to callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); /** set the header callback function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, RestClient::header_callback); /** callback object for headers */ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &ret); /** set content-type header */ curl_slist* header = NULL; header = curl_slist_append(header, ctype_header.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); /** perform the actual query */ res = curl_easy_perform(curl); if (res != CURLE_OK) { ret.body = "Failed to query."; ret.code = -1; return ret; } long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); ret.code = static_cast(http_code); curl_slist_free_all(header); curl_easy_cleanup(curl); curl_global_cleanup(); } return ret; } /** * @brief HTTP PUT method * * @param url to query * @param ctype content type as string * @param data HTTP PUT body * * @return response struct */ RestClient::response RestClient::put(const std::string& url, const std::string& ctype, const std::string& data) { /** create return struct */ RestClient::response ret = {}; /** build content-type header string */ std::string ctype_header = "Content-Type: " + ctype; /** initialize upload object */ RestClient::upload_object up_obj; up_obj.data = data.c_str(); up_obj.length = data.size(); // use libcurl CURL *curl = NULL; CURLcode res = CURLE_OK; curl = curl_easy_init(); if (curl) { /** set basic authentication if present*/ if(RestClient::user_pass.length()>0){ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_USERPWD, RestClient::user_pass.c_str()); } /** set user agent */ curl_easy_setopt(curl, CURLOPT_USERAGENT, RestClient::user_agent); /** set query URL */ curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); /** Now specify we want to PUT data */ curl_easy_setopt(curl, CURLOPT_PUT, 1L); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /** set read callback function */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, RestClient::read_callback); /** set data object to pass to callback function */ curl_easy_setopt(curl, CURLOPT_READDATA, &up_obj); /** set callback function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RestClient::write_callback); /** set data object to pass to callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); /** set the header callback function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, RestClient::header_callback); /** callback object for headers */ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &ret); /** set data size */ curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast(up_obj.length)); /** set content-type header */ curl_slist* header = NULL; header = curl_slist_append(header, ctype_header.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); /** perform the actual query */ res = curl_easy_perform(curl); if (res != CURLE_OK) { ret.body = "Failed to query."; ret.code = -1; return ret; } long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); ret.code = static_cast(http_code); curl_slist_free_all(header); curl_easy_cleanup(curl); curl_global_cleanup(); } return ret; } /** * @brief HTTP DELETE method * * @param url to query * * @return response struct */ RestClient::response RestClient::del(const std::string& url) { /** create return struct */ RestClient::response ret = {}; /** we want HTTP DELETE */ const char* http_delete = "DELETE"; // use libcurl CURL *curl = NULL; CURLcode res = CURLE_OK; curl = curl_easy_init(); if (curl) { /** set basic authentication if present*/ if(RestClient::user_pass.length()>0){ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_USERPWD, RestClient::user_pass.c_str()); } /** set user agent */ curl_easy_setopt(curl, CURLOPT_USERAGENT, RestClient::user_agent); /** set query URL */ curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); /** set HTTP DELETE METHOD */ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_delete); /** set callback function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, RestClient::write_callback); /** set data object to pass to callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); /** set the header callback function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, RestClient::header_callback); /** callback object for headers */ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &ret); /** perform the actual query */ res = curl_easy_perform(curl); if (res != CURLE_OK) { ret.body = "Failed to query."; ret.code = -1; return ret; } long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); ret.code = static_cast(http_code); curl_easy_cleanup(curl); curl_global_cleanup(); } return ret; } /** * @brief write callback function for libcurl * * @param data returned data of size (size*nmemb) * @param size size parameter * @param nmemb memblock parameter * @param userdata pointer to user data to save/work with return data * * @return (size * nmemb) */ size_t RestClient::write_callback(void *data, size_t size, size_t nmemb, void *userdata) { RestClient::response* r; r = reinterpret_cast(userdata); r->body.append(reinterpret_cast(data), size*nmemb); return (size * nmemb); } /** * @brief header callback for libcurl * * @param data returned (header line) * @param size of data * @param nmemb memblock * @param userdata pointer to user data object to save headr data * @return size * nmemb; */ size_t RestClient::header_callback(void *data, size_t size, size_t nmemb, void *userdata) { RestClient::response* r; r = reinterpret_cast(userdata); std::string header(reinterpret_cast(data), size*nmemb); size_t seperator = header.find_first_of(":"); if ( std::string::npos == seperator ) { //roll with non seperated headers... trim(header); if ( 0 == header.length() ){ return (size * nmemb); //blank line; } r->headers[header] = "present"; } else { std::string key = header.substr(0, seperator); trim(key); std::string value = header.substr(seperator + 1); trim (value); r->headers[key] = value; } return (size * nmemb); } /** * @brief read callback function for libcurl * * @param pointer of max size (size*nmemb) to write data to * @param size size parameter * @param nmemb memblock parameter * @param userdata pointer to user data to read data from * * @return (size * nmemb) */ size_t RestClient::read_callback(void *data, size_t size, size_t nmemb, void *userdata) { /** get upload struct */ RestClient::upload_object* u; u = reinterpret_cast(userdata); /** set correct sizes */ size_t curl_size = size * nmemb; size_t copy_size = (u->length < curl_size) ? u->length : curl_size; /** copy data to buffer */ memcpy(data, u->data, copy_size); /** decrement length and increment data pointer */ u->length -= copy_size; u->data += copy_size; /** return copied size */ return copy_size; } mongo-cxx-driver-legacy-1.1.2/src/third_party/restclient/restclient.h000066400000000000000000000046031273231111400260040ustar00rootroot00000000000000/** * @file restclient.h * @brief libcurl wrapper for REST calls * @author Daniel Schauenberg * @version * @date 2010-10-11 */ #ifndef INCLUDE_RESTCLIENT_H_ #define INCLUDE_RESTCLIENT_H_ #include #include #include #include #include #include #include class RestClient { public: /** * public data definitions */ typedef std::map headermap; /** response struct for queries */ typedef struct { int code; std::string body; headermap headers; } response; /** struct used for uploading data */ typedef struct { const char* data; size_t length; } upload_object; /** public methods */ // Auth static void clearAuth(); static void setAuth(const std::string& user,const std::string& password); // HTTP GET static response get(const std::string& url); // HTTP POST static response post(const std::string& url, const std::string& ctype, const std::string& data); // HTTP PUT static response put(const std::string& url, const std::string& ctype, const std::string& data); // HTTP DELETE static response del(const std::string& url); private: // writedata callback function static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata); // header callback function static size_t header_callback(void *ptr, size_t size, size_t nmemb, void *userdata); // read callback function static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userdata); static const char* user_agent; static std::string user_pass; // trim from start static inline std::string <rim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); return s; } // trim from end static inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } }; #endif // INCLUDE_RESTCLIENT_H_ mongo-cxx-driver-legacy-1.1.2/src/third_party/tz/000077500000000000000000000000001273231111400217355ustar00rootroot00000000000000mongo-cxx-driver-legacy-1.1.2/src/third_party/tz/timegm.c000066400000000000000000000442261273231111400233730ustar00rootroot00000000000000/* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson. */ /* ** Leap second handling from Bradley White. ** POSIX-style TZ environment variable handling from Guy Harris. */ /*LINTLIBRARY*/ #include "timegm_private.h" #include "timegm_tzfile.h" #ifndef TZ_ABBR_MAX_LEN #define TZ_ABBR_MAX_LEN 16 #endif /* !defined TZ_ABBR_MAX_LEN */ #ifndef TZ_ABBR_CHAR_SET #define TZ_ABBR_CHAR_SET \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" #endif /* !defined TZ_ABBR_CHAR_SET */ #ifndef TZ_ABBR_ERR_CHAR #define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ /* ** SunOS 4.1.1 headers lack O_BINARY. */ #ifdef O_BINARY #define OPEN_MODE (O_RDONLY | O_BINARY) #endif /* defined O_BINARY */ #ifndef O_BINARY #define OPEN_MODE O_RDONLY #endif /* !defined O_BINARY */ #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: ** 1. They might reference tzname[0] before calling tzset (explicitly ** or implicitly). ** 2. They might reference tzname[1] before calling tzset (explicitly ** or implicitly). ** 3. They might reference tzname[1] after setting to a time zone ** in which Daylight Saving Time is never observed. ** 4. They might reference tzname[0] after setting to a time zone ** in which Standard Time is never observed. ** 5. They might reference tm.TM_ZONE after calling offtime. ** What's best to do in the above cases is open to debate; ** for now, we just set things up so that in any of the five cases ** WILDABBR is used. Another possibility: initialize tzname[0] to the ** string "tzname[0] used before set", and similarly for the other cases. ** And another: initialize tzname[0] to "ERA", with an explanation in the ** manual page of what this "time zone abbreviation" means (doing this so ** that tzname[0] has the "normal" length of three characters). */ #define WILDABBR " " #endif /* !defined WILDABBR */ static const char wildabbr[] = WILDABBR; static const char gmt[] = "GMT"; struct ttinfo { /* time type information */ int_fast32_t tt_gmtoff; /* UT offset in seconds */ int tt_isdst; /* used to set tm_isdst */ int tt_abbrind; /* abbreviation list index */ int tt_ttisstd; /* TRUE if transition is std time */ int tt_ttisgmt; /* TRUE if transition is UT */ }; struct lsinfo { /* leap second information */ time_t ls_trans; /* transition time */ int_fast64_t ls_corr; /* correction to apply */ }; #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) #ifdef TZNAME_MAX #define MY_TZNAME_MAX TZNAME_MAX #endif /* defined TZNAME_MAX */ #ifndef TZNAME_MAX #define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ struct state { int leapcnt; int timecnt; int typecnt; int charcnt; int goback; int goahead; time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; int defaulttype; /* for early times or if no transitions */ }; struct rule { int r_type; /* type of rule--see below */ int r_day; /* day number of rule */ int r_week; /* week number of rule */ int r_mon; /* month number of rule */ int_fast32_t r_time; /* transition time of rule */ }; #define JULIAN_DAY 0 /* Jn - Julian day */ #define DAY_OF_YEAR 1 /* n - day of year */ #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ /* ** Prototypes for static functions. */ static void gmtload(struct state * sp); static struct tm * gmtsub(const time_t * timep, int_fast32_t offset, struct tm * tmp); static int increment_overflow(int * number, int delta); static int leaps_thru_end_of(int y) ATTRIBUTE_PURE; static int increment_overflow32(int_fast32_t * number, int delta); static int increment_overflow_time(time_t *t, int_fast32_t delta); static int normalize_overflow32(int_fast32_t * tensptr, int * unitsptr, int base); static int normalize_overflow(int * tensptr, int * unitsptr, int base); static time_t time1(struct tm * tmp, struct tm * (*funcp)(const time_t *, int_fast32_t, struct tm *), int_fast32_t offset); static time_t time2(struct tm *tmp, struct tm * (*funcp)(const time_t *, int_fast32_t, struct tm*), int_fast32_t offset, int * okayp); static time_t time2sub(struct tm *tmp, struct tm * (*funcp)(const time_t *, int_fast32_t, struct tm*), int_fast32_t offset, int * okayp, int do_norm_secs); static struct tm * timesub(const time_t * timep, int_fast32_t offset, const struct state * sp, struct tm * tmp); static int tmcomp(const struct tm * atmp, const struct tm * btmp); static struct state gmtmem; #define gmtptr (&gmtmem) static int gmt_is_set; static const int mon_lengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; static const int year_lengths[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; static void gmtload(struct state *const sp) { memset(sp, 0, sizeof(struct state)); sp->typecnt = 1; sp->charcnt = 4; sp->chars[0] = 'G'; sp->chars[1] = 'M'; sp->chars[2] = 'T'; } /* ** gmtsub is to gmtime as localsub is to localtime. */ static struct tm * gmtsub(const time_t *const timep, const int_fast32_t offset, struct tm *const tmp) { register struct tm * result; if (!gmt_is_set) { gmt_is_set = TRUE; gmtload(gmtptr); } result = timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as ** "UT+xxxx" or "UT-xxxx" if offset is non-zero, ** but this is no time for a treasure hunt. */ tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt; #endif /* defined TM_ZONE */ return result; } /* ** Return the number of leap years through the end of the given year ** where, to make the math easy, the answer for year zero is defined as zero. */ static int leaps_thru_end_of(register const int y) { return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1); } static struct tm * timesub(const time_t *const timep, const int_fast32_t offset, register const struct state *const sp, register struct tm *const tmp) { register const struct lsinfo * lp; register time_t tdays; register int idays; /* unsigned would be so 2003 */ register int_fast64_t rem; int y; register const int * ip; register int_fast64_t corr; register int hit; register int i; corr = 0; hit = 0; i = (sp == NULL) ? 0 : sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { if (*timep == lp->ls_trans) { hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr); if (hit) while (i > 0 && sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { ++hit; --i; } } corr = lp->ls_corr; break; } } y = EPOCH_YEAR; tdays = *timep / SECSPERDAY; rem = *timep - tdays * SECSPERDAY; while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { int newy; register time_t tdelta; register int idelta; register int leapdays; tdelta = tdays / DAYSPERLYEAR; if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta) && tdelta <= INT_MAX)) return NULL; idelta = tdelta; if (idelta == 0) idelta = (tdays < 0) ? -1 : 1; newy = y; if (increment_overflow(&newy, idelta)) return NULL; leapdays = leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1); tdays -= ((time_t) newy - y) * DAYSPERNYEAR; tdays -= leapdays; y = newy; } { register int_fast32_t seconds; seconds = tdays * SECSPERDAY; tdays = seconds / SECSPERDAY; rem += seconds - tdays * SECSPERDAY; } /* ** Given the range, we can now fearlessly cast... */ idays = tdays; rem += offset - corr; while (rem < 0) { rem += SECSPERDAY; --idays; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++idays; } while (idays < 0) { if (increment_overflow(&y, -1)) return NULL; idays += year_lengths[isleap(y)]; } while (idays >= year_lengths[isleap(y)]) { idays -= year_lengths[isleap(y)]; if (increment_overflow(&y, 1)) return NULL; } tmp->tm_year = y; if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) return NULL; tmp->tm_yday = idays; /* ** The "extra" mods below avoid overflow problems. */ tmp->tm_wday = EPOCH_WDAY + ((y - EPOCH_YEAR) % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK) + leaps_thru_end_of(y - 1) - leaps_thru_end_of(EPOCH_YEAR - 1) + idays; tmp->tm_wday %= DAYSPERWEEK; if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; tmp->tm_hour = (int) (rem / SECSPERHOUR); rem %= SECSPERHOUR; tmp->tm_min = (int) (rem / SECSPERMIN); /* ** A positive leap second requires a special ** representation. This uses "... ??:59:60" et seq. */ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; ip = mon_lengths[isleap(y)]; for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) idays -= ip[tmp->tm_mon]; tmp->tm_mday = (int) (idays + 1); tmp->tm_isdst = 0; #ifdef TM_GMTOFF tmp->TM_GMTOFF = offset; #endif /* defined TM_GMTOFF */ return tmp; } /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob ** Kridle's (so its said...) from a long time ago. ** It does a binary search of the time_t space. Since time_t's are ** just 32 bits, its a max of 32 iterations (even at 64 bits it ** would still be very reasonable). */ #ifndef WRONG #define WRONG (-1) #endif /* !defined WRONG */ /* ** Normalize logic courtesy Paul Eggert. */ static int increment_overflow(int *const ip, int j) { register int const i = *ip; /* ** If i >= 0 there can only be overflow if i + j > INT_MAX ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. ** If i < 0 there can only be overflow if i + j < INT_MIN ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. */ if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) return TRUE; *ip += j; return FALSE; } static int increment_overflow32(int_fast32_t *const lp, int const m) { register int_fast32_t const l = *lp; if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) return TRUE; *lp += m; return FALSE; } static int increment_overflow_time(time_t *tp, int_fast32_t j) { /* ** This is like ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...', ** except that it does the right thing even if *tp + j would overflow. */ if (! (j < 0 ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp) : *tp <= time_t_max - j)) return TRUE; *tp += j; return FALSE; } static int normalize_overflow(int *const tensptr, int *const unitsptr, const int base) { register int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow(tensptr, tensdelta); } static int normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr, const int base) { register int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow32(tensptr, tensdelta); } static int tmcomp(register const struct tm *const atmp, register const struct tm *const btmp) { register int result; if (atmp->tm_year != btmp->tm_year) return atmp->tm_year < btmp->tm_year ? -1 : 1; if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_min - btmp->tm_min)) == 0) result = atmp->tm_sec - btmp->tm_sec; return result; } static time_t time2sub(struct tm *const tmp, struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset, int *const okayp, const int do_norm_secs) { register const struct state * sp; register int dir; register int i, j; register int saved_seconds; register int_fast32_t li; register time_t lo; register time_t hi; int_fast32_t y; time_t newt; time_t t; struct tm yourtm, mytm; *okayp = FALSE; yourtm = *tmp; if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) return WRONG; } if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) return WRONG; if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) return WRONG; y = yourtm.tm_year; if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow32(&y, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { if (increment_overflow32(&y, -1)) return WRONG; li = y + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(li)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { li = y + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(li)]; if (increment_overflow32(&y, 1)) return WRONG; } for ( ; ; ) { i = mon_lengths[isleap(y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow32(&y, 1)) return WRONG; } } if (increment_overflow32(&y, -TM_YEAR_BASE)) return WRONG; yourtm.tm_year = y; if (yourtm.tm_year != y) return WRONG; if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; else if (y + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. ** Set tm_sec to 59 instead. ** This assumes that the minimum representable time is ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) return WRONG; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; yourtm.tm_sec = 0; } /* ** Do a binary search (this works whatever time_t's type is). */ if (!TYPE_SIGNED(time_t)) { lo = 0; hi = lo - 1; } else { lo = 1; for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) lo *= 2; hi = -(lo + 1); } for ( ; ; ) { t = lo / 2 + hi / 2; if (t < lo) t = lo; else if (t > hi) t = hi; if ((*funcp)(&t, offset, &mytm) == NULL) { /* ** Assume that t is too extreme to be represented in ** a struct tm; arrange things so that it is less ** extreme on the next pass. */ dir = (t > 0) ? 1 : -1; } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (t == lo) { if (t == time_t_max) return WRONG; ++t; ++lo; } else if (t == hi) { if (t == time_t_min) return WRONG; --t; --hi; } if (lo > hi) return WRONG; if (dir > 0) hi = t; else lo = t; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) break; /* ** Right time, wrong type. ** Hunt for right time, right type. ** It's okay to guess wrong since the guess ** gets checked. */ sp = (const struct state *) gmtptr; if (sp == NULL) return WRONG; for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; for (j = sp->typecnt - 1; j >= 0; --j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; if ((*funcp)(&newt, offset, &mytm) == NULL) continue; if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) continue; /* ** We have a match. */ t = newt; goto label; } } return WRONG; } label: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; if ((*funcp)(&t, offset, tmp)) *okayp = TRUE; return t; } static time_t time2(struct tm * const tmp, struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset, int *const okayp) { time_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ t = time2sub(tmp, funcp, offset, okayp, FALSE); return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); } static time_t time1(struct tm *const tmp, struct tm *(*const funcp) (const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset) { register time_t t; register const struct state * sp; register int samei, otheri; register int sameind, otherind; register int i; register int nseen; int seen[TZ_MAX_TYPES]; int types[TZ_MAX_TYPES]; int okay; if (tmp == NULL) { errno = EINVAL; return WRONG; } if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay); if (okay) return t; if (tmp->tm_isdst < 0) #ifdef PCTS /* ** POSIX Conformance Test Suite code courtesy Grant Sullivan. */ tmp->tm_isdst = 0; /* reset to std and try again */ #else return t; #endif /* !defined PCTS */ /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. ** We try to divine the type they started from and adjust to the ** type they need. */ sp = (const struct state *) gmtptr; if (sp == NULL) return WRONG; for (i = 0; i < sp->typecnt; ++i) seen[i] = FALSE; nseen = 0; for (i = sp->timecnt - 1; i >= 0; --i) if (!seen[sp->types[i]]) { seen[sp->types[i]] = TRUE; types[nseen++] = sp->types[i]; } for (sameind = 0; sameind < nseen; ++sameind) { samei = types[sameind]; if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otherind = 0; otherind < nseen; ++otherind) { otheri = types[otherind]; if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; t = time2(tmp, funcp, offset, &okay); if (okay) return t; tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } return WRONG; } time_t timegm(struct tm *const tmp) { if (tmp != NULL) tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L); } mongo-cxx-driver-legacy-1.1.2/src/third_party/tz/timegm_private.h000066400000000000000000000106461273231111400251310ustar00rootroot00000000000000#ifndef PRIVATE_H #define PRIVATE_H /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson. */ /* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. ** Do NOT copy it to any system include directory. ** Thank you! */ #ifndef HAVE_STDINT_H #define HAVE_STDINT_H 1 #endif #define GRANDPARENTED "Local time zone must be set--see zic manual page" /* ** Nested includes */ #include "errno.h" #include "string.h" #include "limits.h" /* for CHAR_BIT et al. */ #include "time.h" /* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ #define is_digit(c) ((unsigned)(c) - '0' <= 9) /* ** Define HAVE_STDINT_H's default value here, rather than at the ** start, since __GLIBC__'s value depends on previously-included ** files. ** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.) */ #ifndef HAVE_STDINT_H #define HAVE_STDINT_H \ (199901 <= __STDC_VERSION__ || \ 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) #endif /* !defined HAVE_STDINT_H */ #if HAVE_STDINT_H #include "stdint.h" #endif /* !HAVE_STDINT_H */ #ifndef HAVE_INTTYPES_H # define HAVE_INTTYPES_H HAVE_STDINT_H #endif #if HAVE_INTTYPES_H # include #endif #ifndef INT_FAST64_MAX /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ #if defined LLONG_MAX || defined __LONG_LONG_MAX__ typedef long long int_fast64_t; # ifdef LLONG_MAX # define INT_FAST64_MIN LLONG_MIN # define INT_FAST64_MAX LLONG_MAX # else # define INT_FAST64_MIN __LONG_LONG_MIN__ # define INT_FAST64_MAX __LONG_LONG_MAX__ # endif # define SCNdFAST64 "lld" #else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #if (LONG_MAX >> 31) < 0xffffffff Please use a compiler that supports a 64-bit integer type (or wider); you may need to compile with "-DHAVE_STDINT_H". #endif /* (LONG_MAX >> 31) < 0xffffffff */ typedef long int_fast64_t; # define INT_FAST64_MIN LONG_MIN # define INT_FAST64_MAX LONG_MAX # define SCNdFAST64 "ld" #endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #endif /* !defined INT_FAST64_MAX */ #ifndef INT_FAST32_MAX # if INT_MAX >> 31 == 0 typedef long int_fast32_t; # else typedef int int_fast32_t; # endif #endif #ifndef INTMAX_MAX # if defined LLONG_MAX || defined __LONG_LONG_MAX__ typedef long long intmax_t; # define strtoimax strtoll # define PRIdMAX "lld" # ifdef LLONG_MAX # define INTMAX_MAX LLONG_MAX # define INTMAX_MIN LLONG_MIN # else # define INTMAX_MAX __LONG_LONG_MAX__ # define INTMAX_MIN __LONG_LONG_MIN__ # endif # else typedef long intmax_t; # define strtoimax strtol # define PRIdMAX "ld" # define INTMAX_MAX LONG_MAX # define INTMAX_MIN LONG_MIN # endif #endif #ifndef UINTMAX_MAX # if defined ULLONG_MAX || defined __LONG_LONG_MAX__ typedef unsigned long long uintmax_t; # define PRIuMAX "llu" # else typedef unsigned long uintmax_t; # define PRIuMAX "lu" # endif #endif #ifndef INT32_MAX #define INT32_MAX 0x7fffffff #endif /* !defined INT32_MAX */ #ifndef INT32_MIN #define INT32_MIN (-1 - INT32_MAX) #endif /* !defined INT32_MIN */ #ifndef SIZE_MAX #define SIZE_MAX ((size_t) -1) #endif #if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define ATTRIBUTE_CONST __attribute__ ((const)) # define ATTRIBUTE_PURE __attribute__ ((__pure__)) # define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) #else # define ATTRIBUTE_CONST /* empty */ # define ATTRIBUTE_PURE /* empty */ # define ATTRIBUTE_FORMAT(spec) /* empty */ #endif #if !defined _Noreturn && __STDC_VERSION__ < 201112 # if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) # define _Noreturn __attribute__ ((__noreturn__)) # else # define _Noreturn # endif #endif #if __STDC_VERSION__ < 199901 && !defined restrict # define restrict /* empty */ #endif #ifndef TRUE #define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE #define FALSE 0 #endif /* !defined FALSE */ #ifndef TYPE_BIT #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #endif /* !defined TYPE_BIT */ #ifndef TYPE_SIGNED #define TYPE_SIGNED(type) (((type) -1) < 0) #endif /* !defined TYPE_SIGNED */ /* The minimum and maximum finite time values. */ static time_t const time_t_min = (TYPE_SIGNED(time_t) ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) : 0); static time_t const time_t_max = (TYPE_SIGNED(time_t) ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)) : -1); #endif /* !defined PRIVATE_H */ mongo-cxx-driver-legacy-1.1.2/src/third_party/tz/timegm_tzfile.h000066400000000000000000000045101273231111400247450ustar00rootroot00000000000000#ifndef TZFILE_H #define TZFILE_H /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson. */ /* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. ** Do NOT copy it to any system include directory. ** Thank you! */ /* ** In the current implementation, "tzset()" refuses to deal with files that ** exceed any of the limits below. */ #ifndef TZ_MAX_TIMES #define TZ_MAX_TIMES 2000 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES /* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ #define SECSPERMIN 60 #define MINSPERHOUR 60 #define HOURSPERDAY 24 #define DAYSPERWEEK 7 #define DAYSPERNYEAR 365 #define DAYSPERLYEAR 366 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) #define MONSPERYEAR 12 #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 #define TM_WEDNESDAY 3 #define TM_THURSDAY 4 #define TM_FRIDAY 5 #define TM_SATURDAY 6 #define TM_JANUARY 0 #define TM_FEBRUARY 1 #define TM_MARCH 2 #define TM_APRIL 3 #define TM_MAY 4 #define TM_JUNE 5 #define TM_JULY 6 #define TM_AUGUST 7 #define TM_SEPTEMBER 8 #define TM_OCTOBER 9 #define TM_NOVEMBER 10 #define TM_DECEMBER 11 #define TM_YEAR_BASE 1900 #define EPOCH_YEAR 1970 #define EPOCH_WDAY TM_THURSDAY #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) /* ** Since everything in isleap is modulo 400 (or a factor of 400), we know that ** isleap(y) == isleap(y % 400) ** and so ** isleap(a + b) == isleap((a + b) % 400) ** or ** isleap(a + b) == isleap(a % 400 + b % 400) ** This is true even if % means modulo rather than Fortran remainder ** (which is allowed by C89 but not C99). ** We use this to avoid addition overflow problems. */ #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) #endif /* !defined TZFILE_H */