diff --git a/.atom/config.cson b/.atom/config.cson deleted file mode 100644 index 385231685..000000000 --- a/.atom/config.cson +++ /dev/null @@ -1,22 +0,0 @@ -"*": - "atom-beautify": - c: - beautify_on_save: true - configPath: "src/uncrustify.cfg" - cpp: - beautify_on_save: true - configPath: "src/uncrustify.cfg" - python: {} - editor: - autoIndentOnPaste: false - fontSize: 18 - preferredLineLength: 88 - scrollPastEnd: true - showInvisibles: true - softWrap: true - softWrapAtPreferredLineLength: true - tabLength: 4 - tabType: "soft" - "python-black": - fmtOnSave: true - lineLength: 88 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..2c431b0bf --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 00deb32f7..000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,134 +0,0 @@ -# Deploy tagged releases. - -name: Deploy Release - -on: - push: - tags: - - '*' - -env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }} - -jobs: - sdist: - name: Python source dist - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - name: Install Dependencies - run: pip install twine - - name: Pull Dependency Image - run: docker pull hpc4cmb/toast-deps-py37:latest - - name: Create dist directory - run: mkdir -p dist && rm -f dist/* - - name: Build source package - run: docker run -v "$(pwd)":/home/toast hpc4cmb/toast-deps-py37:latest /home/toast/wheels/build_sdist.sh - - name: Upload to PyPI - run: | - python -m twine upload dist/toast*.tar.gz - wheels-36: - name: Python 3.6 wheels for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - env: - CIBW_BUILD: cp36-macosx_x86_64 cp36-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 - CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.7' - - name: Install cibuildwheel - run: | - python -m pip install twine cibuildwheel==1.6.3 - - name: Build wheel - run: | - python -m cibuildwheel --output-dir wheelhouse - - name: Upload to PyPI - run: | - python -m twine upload wheelhouse/toast*.whl - wheels-37: - name: Python 3.7 wheels for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - env: - CIBW_BUILD: cp37-macosx_x86_64 cp37-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 - CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.7' - - name: Install cibuildwheel - run: | - python -m pip install twine cibuildwheel==1.6.3 - - name: Build wheel - run: | - python -m cibuildwheel --output-dir wheelhouse - - name: Upload to PyPI - run: | - python -m twine upload wheelhouse/toast*.whl - wheels-38: - name: Python 3.8 wheels for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - env: - CIBW_BUILD: cp38-macosx_x86_64 cp38-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 - CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.7' - - name: Install cibuildwheel - run: | - python -m pip install twine cibuildwheel==1.6.3 - - name: Build wheel - run: | - python -m cibuildwheel --output-dir wheelhouse - - name: Upload to PyPI - run: | - python -m twine upload wheelhouse/toast*.whl diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..a6167c42f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,60 @@ +name: Deploy Documentation + +on: + workflow_dispatch: + push: + tags: + - '*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + update_docs: + name: Build and Deploy Documentation + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Conda Base + run: | + sudo rm -rf /usr/share/miniconda \ + && sudo rm -rf /usr/local/miniconda \ + && curl -SL -o miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh \ + && bash miniforge.sh -b -f -p ~/conda \ + && source ~/conda/etc/profile.d/conda.sh \ + && conda activate base \ + && conda update -n base --yes conda + + - name: Create Build Env + run: | + source ~/conda/etc/profile.d/conda.sh \ + && ./platforms/conda_dev_setup.sh docs 3.13 + + - name: Install Package + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate docs \ + && ./platforms/conda.sh \ + && python3 -c 'import toast' + + - name: Install Doc Dependencies + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate docs \ + && conda install --yes --file docs/doc_requirements.txt \ + && pip install mkdocs-print-site-plugin \ + && git config user.name 'github-actions[bot]' \ + && git config user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Deploy Docs + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate docs \ + && cd docs \ + && mkdocs gh-deploy --force diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c7fb77db2..da1b61130 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,71 +1,116 @@ # Use pre-built docker containers to run our unit tests on different python versions. +# +# In general, we try to run on: +# - The oldest supported python +# - The latest stable python that is the common default on most systems and conda +# - (During transitions) The newly released bleeding edge python name: Run Test Suite on: push: - branches: [ master ] + branches: + - master pull_request: - branches: [ master ] + branches: + - master + - toast3 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - py36: - name: Python 3.6 - runs-on: ubuntu-latest - steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.4.0 - with: - access_token: ${{ github.token }} - - name: Checkout - uses: actions/checkout@v2 - - name: Pull Dependency Image - run: docker pull hpc4cmb/toast-deps-py36:latest - - name: Compile - run: docker run -v "$(pwd)":/home/toast --name="test_py36" hpc4cmb/toast-deps-py36:latest /home/toast/platforms/install_test_runner.sh && docker commit -m "test runner" test_py36 test_runner:py36 - - name: Test Documentation Build - run: docker run -v "$(pwd)":/home/toast test_runner:py36 /home/toast/docs/build_docs.sh - - name: Run Serial Tests - run: docker run -e MPI_DISABLE=1 test_runner:py36 python -c 'import toast.tests; toast.tests.run()' - - name: Run MPI Tests - run: docker run test_runner:py36 mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' - py37: - name: Python 3.7 - runs-on: ubuntu-latest - steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.4.0 - with: - access_token: ${{ github.token }} - - name: Checkout - uses: actions/checkout@v2 - - name: Pull Dependency Image - run: docker pull hpc4cmb/toast-deps-py37:latest - - name: Compile - run: docker run -v "$(pwd)":/home/toast --name="test_py37" hpc4cmb/toast-deps-py37:latest /home/toast/platforms/install_test_runner.sh && docker commit -m "test runner" test_py37 test_runner:py37 - - name: Test Documentation Build - run: docker run -v "$(pwd)":/home/toast test_runner:py37 /home/toast/docs/build_docs.sh - - name: Run Serial Tests - run: docker run -e MPI_DISABLE=1 test_runner:py37 python -c 'import toast.tests; toast.tests.run()' - - name: Run MPI Tests - run: docker run test_runner:py37 mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' - py38: - name: Python 3.8 - runs-on: ubuntu-latest + test: + name: Tests on ${{ matrix.arch }} with Conda Python-${{ matrix.python }} + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash -l {0} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + python: "3.9" + arch: Linux-x86_64 + ompdisable: 0 + - os: ubuntu-latest + python: "3.12" + arch: Linux-x86_64 + ompdisable: 0 + - os: ubuntu-latest + python: "3.13" + arch: Linux-x86_64 + ompdisable: 0 + - os: macos-latest + python: "3.10" + arch: MacOSX-x86_64 + ompdisable: 1 + - os: macos-latest + python: "3.13" + arch: MacOSX-x86_64 + ompdisable: 1 + - os: macos-latest + python: "3.10" + arch: MacOSX-arm64 + ompdisable: 1 + - os: macos-latest + python: "3.13" + arch: MacOSX-arm64 + ompdisable: 1 steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.4.0 - with: - access_token: ${{ github.token }} - name: Checkout - uses: actions/checkout@v2 - - name: Pull Dependency Image - run: docker pull hpc4cmb/toast-deps-py38:latest - - name: Compile - run: docker run -v "$(pwd)":/home/toast --name="test_py38" hpc4cmb/toast-deps-py38:latest /home/toast/platforms/install_test_runner.sh && docker commit -m "test runner" test_py38 test_runner:py38 - - name: Test Documentation Build - run: docker run -v "$(pwd)":/home/toast test_runner:py38 /home/toast/docs/build_docs.sh + uses: actions/checkout@v4 + + - name: Setup Conda Base + run: | + sudo rm -rf /usr/share/miniconda \ + && sudo rm -rf /usr/local/miniconda \ + && curl -SL -o miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-${{ matrix.arch }}.sh \ + && bash miniforge.sh -b -f -p ~/conda \ + && source ~/conda/etc/profile.d/conda.sh \ + && conda activate base \ + && conda update -n base --yes conda + + - name: Check Conda Config + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate base \ + && conda info \ + && conda list \ + && conda config --show-sources \ + && conda config --show + + - name: Create Conda Env + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate base \ + && ./platforms/conda_dev_setup.sh toast ${{ matrix.python }} yes \ + && python3 -m pip install 'spt3g==1.0.0' + + - name: Install + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate toast \ + && export TOAST_BUILD_DISABLE_OPENMP=${{ matrix.ompdisable }} \ + && ./platforms/conda.sh + - name: Run Serial Tests - run: docker run -e MPI_DISABLE=1 test_runner:py38 python -c 'import toast.tests; toast.tests.run()' + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate toast \ + && export OMP_NUM_THREADS=2 \ + && export MPI_DISABLE=1 \ + && python3 -c 'import toast.tests; toast.tests.run()' \ + && unset MPI_DISABLE \ + && unset OMP_NUM_THREADS + - name: Run MPI Tests - run: docker run test_runner:py38 mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' + run: | + source ~/conda/etc/profile.d/conda.sh \ + && conda activate toast \ + && export OMP_NUM_THREADS=1 \ + && mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' \ + && unset OMP_NUM_THREADS + diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d36da866c..54fcc9f2a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -1,134 +1,182 @@ -name: Test Binary Wheels +name: Binary Wheels -# Uncomment here for testing and comment out schedule below. -# on: -# push: -# branches: [ master ] -# pull_request: -# branches: [ master ] - -# Uncomment here for production and comment out push / PR above. on: - schedule: - - cron: '0 4 * * *' + # workflow_dispatch: + # FIXME: Remove these lines once this workflow merged + # to main branch. + # pull_request: + # branches: + # - toast3 + # FIXME: Remove tags stanza after we are doing releases + # from main, and restore release stanza. + push: + tags: + - '*' + # release: + # types: [ published ] + + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - sdist: - name: Python source dist - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Pull Dependency Image - run: docker pull hpc4cmb/toast-deps-py37:latest - - name: Create dist directory - run: mkdir -p dist && rm -f dist/* - - name: Build source package - run: docker run -v "$(pwd)":/home/toast hpc4cmb/toast-deps-py37:latest /home/toast/wheels/build_sdist.sh - - uses: actions/upload-artifact@v2 - with: - name: sdist - path: ./dist/toast*.gz - wheels-py36: - name: Python 3.6 wheels for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - env: - CIBW_BUILD: cp36-macosx_x86_64 cp36-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 - CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Install Python - with: - python-version: '3.7' - - name: Install cibuildwheel - run: | - python -m pip install cibuildwheel==1.6.3 - - name: Build wheel - run: | - python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 - with: - name: wheels - path: ./wheelhouse/toast*.whl - wheels-py37: - name: Python 3.7 wheels for ${{ matrix.os }} + build_wheels: + name: Build wheel for cp${{ matrix.python }}-${{ matrix.builder }}_${{ matrix.arch }} runs-on: ${{ matrix.os }} strategy: + # Ensure that a wheel builder finishes even if another fails. Useful for + # debugging multiple problems in parallel. + fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + include: + # Linux 64 bit manylinux + - os: ubuntu-latest + arch: x86_64 + python: 39 + builder: manylinux + - os: ubuntu-latest + arch: x86_64 + python: 310 + builder: manylinux + - os: ubuntu-latest + arch: x86_64 + python: 311 + builder: manylinux + - os: ubuntu-latest + arch: x86_64 + python: 312 + builder: manylinux + - os: ubuntu-latest + arch: x86_64 + python: 313 + builder: manylinux + + # MacOS x86_64. The macos-13 runner is the last + # Intel-based runner version. At some point we'll + # need to switch to macos-latest and test cross compiling. + - os: macos-13 + arch: x86_64 + python: 310 + builder: macosx + deploy: 13.0 + - os: macos-13 + arch: x86_64 + python: 311 + builder: macosx + deploy: 13.0 + - os: macos-13 + arch: x86_64 + python: 312 + builder: macosx + deploy: 13.0 + - os: macos-13 + arch: x86_64 + python: 313 + builder: macosx + deploy: 13.0 + + # MacOS arm64 + - os: macos-latest + arch: arm64 + python: 310 + builder: macosx + deploy: 14.0 + - os: macos-latest + arch: arm64 + python: 311 + builder: macosx + deploy: 14.0 + - os: macos-latest + arch: arm64 + python: 312 + builder: macosx + deploy: 14.0 + - os: macos-latest + arch: arm64 + python: 313 + builder: macosx + deploy: 14.0 env: - CIBW_BUILD: cp37-macosx_x86_64 cp37-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 + CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.builder }}_${{ matrix.arch }} + CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.builder }}_2_28 + CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.builder }}_2_28 CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' + CIBW_ENVIRONMENT_LINUX: > + TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON + TOAST_BUILD_TOAST_STATIC_DEPS=ON + TOAST_BUILD_BLAS_LIBRARIES='-L/usr/local/lib -lopenblas -fopenmp -lm -lgfortran' + TOAST_BUILD_LAPACK_LIBRARIES='-L/usr/local/lib -lopenblas -fopenmp -lm -lgfortran' + TOAST_BUILD_FFTW_ROOT=/usr/local + TOAST_BUILD_AATM_ROOT=/usr/local + TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS=/usr/local/include + TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS=/usr/local/lib + CIBW_ENVIRONMENT_MACOS: > + MACOSX_DEPLOYMENT_TARGET=${{ matrix.deploy }} + TOAST_BUILD_CMAKE_C_COMPILER=clang + TOAST_BUILD_CMAKE_CXX_COMPILER=clang++ + TOAST_BUILD_CMAKE_C_FLAGS='-O3 -fPIC' + TOAST_BUILD_CMAKE_CXX_FLAGS='-O3 -fPIC -std=c++11 -stdlib=libc++' + TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON + TOAST_BUILD_DISABLE_OPENMP=1 + TOAST_BUILD_BLAS_LIBRARIES='/usr/local/lib/libopenblas.dylib' + TOAST_BUILD_LAPACK_LIBRARIES='/usr/local/lib/libopenblas.dylib' + TOAST_BUILD_FFTW_ROOT=/usr/local + TOAST_BUILD_AATM_ROOT=/usr/local + TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS=/usr/local/include + TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS=/usr/local/lib + CIBW_BEFORE_BUILD_LINUX: ./packaging/wheels/install_deps_linux.sh + CIBW_BEFORE_BUILD_MACOS: ./packaging/wheels/install_deps_osx.sh + CIBW_BEFORE_TEST: export OMP_NUM_THREADS=2 + CIBW_TEST_COMMAND_LINUX: > + tst=$(dirname $(python -c 'import toast; print(toast.__file__)')) && + echo "Toast test install at ${tst}" && + ldd ${tst}/_libtoast.cpython* && + source {project}/packaging/wheels/cibw_run_tests.sh + CIBW_TEST_COMMAND_MACOS: > + tst=$(dirname $(python -c 'import toast; print(toast.__file__)')) && + echo "Toast test install at ${tst}" && + otool -L ${tst}/_libtoast.cpython* && + source {project}/packaging/wheels/cibw_run_tests.sh steps: - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 name: Install Python with: - python-version: '3.7' + python-version: '3.12' + - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.6.3 + python -m pip install cibuildwheel==2.23.3 + - name: Build wheel run: | python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 + + - uses: actions/upload-artifact@v4 with: - name: wheels - path: ./wheelhouse/toast*.whl - wheels-py38: - name: Python 3.8 wheels for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - env: - CIBW_BUILD: cp38-macosx_x86_64 cp38-manylinux_x86_64 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2010 - CIBW_MANYLINUX_I686_IMAGE: manylinux2010 - CIBW_BUILD_VERBOSITY: 3 - CIBW_ENVIRONMENT_LINUX: "PATH=/usr/lib64/mpich-3.2/bin:${PATH} TOAST_BUILD_BLAS_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON" - CIBW_ENVIRONMENT_MACOS: - CIBW_BEFORE_BUILD_LINUX: ./wheels/install_deps_linux.sh - CIBW_BEFORE_BUILD_MACOS: ./wheels/install_deps_osx.sh - CIBW_BEFORE_TEST: pip3 install numpy && pip3 install mpi4py - CIBW_TEST_COMMAND: export OMP_NUM_THREADS=2; python -c 'import toast.tests; toast.tests.run()' + name: toast-cp${{ matrix.python }}-${{ matrix.builder }}_${{ matrix.arch }} + path: ./wheelhouse/toast*cp${{ matrix.python }}-${{ matrix.builder }}*${{ matrix.arch }}*.whl + + # FIXME: before merge to main, comment out this whole block when + # testing without upload. + upload_pypi: + needs: build_wheels + runs-on: ubuntu-latest + permissions: + id-token: write + # FIXME: restore release / published conditional here after merge + # to main. + # if: github.event_name == 'release' && github.event.action == 'published' steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Install Python + - uses: actions/download-artifact@v4 with: - python-version: '3.7' - - name: Install cibuildwheel - run: | - python -m pip install cibuildwheel==1.6.3 - - name: Build wheel - run: | - python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 - with: - name: wheels - path: ./wheelhouse/toast*.whl + # Unpacks all artifacts into dist/ + pattern: toast-* + path: dist + merge-multiple: true + + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore index 4598d4da7..289dbb88d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,6 @@ # backup saves *~ -/doc/xml -/doc/sphinx/_build -/doc/_build - # Byte-compiled / optimized / DLL files # __pycache__/ # *.py[cod] @@ -36,3 +32,10 @@ src/libtoast/src/version.cpp # Jupyter notebooks .ipynb_checkpoints __pycache__ + +# Clion config and build directories +.idea +cmake-* + +# VScode config files +*.vscode diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..7bcf295b6 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,26 @@ +# Required +version: 2 + +# Formats +formats: [] + +# Set the version of Python and other tools you might need +build: + os: ubuntu-20.04 + apt_packages: + - libfftw3-dev + - libopenblas-dev + tools: + python: "3.9" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/rtd_requirements.txt + - requirements: wheels/build_requirements.txt + - method: pip + path: . diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c4df69bf..fd5577c95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,14 @@ # This minimum version is mostly set in order to get a newer version # of the FindMPI check. Note that you can easily install a newer cmake version # using conda or pip. -cmake_minimum_required(VERSION 3.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) foreach(policy CMP0048 CMP0074 CMP0077 CMP0063 + CMP0094 ) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) @@ -28,6 +29,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Set symbol visibility to hidden to be consistent with pybind11 set(CMAKE_CXX_VISIBILITY_PRESET hidden) +# pybind11 enables IPO by default. This can cause problems with some +# compilers. Remove this if we find a better workaround: +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) + # Auxiliary files list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") @@ -54,17 +59,90 @@ if(NOT TOAST_STATIC_DEPS AND NOT $ENV{TOAST_STATIC_DEPS} STREQUAL "") endif() # OpenMP -find_package(OpenMP) +if(NOT DISABLE_OPENMP) + find_package(OpenMP) +endif() + +if(OpenMP_CXX_FOUND) + message(STATUS + "Found OpenMP version: \"" ${OpenMP_CXX_VERSION} + "\" spec date " ${OpenMP_CXX_SPEC_DATE} + ) + # Allow the user to force enabling of target offload. Some compilers support all + # the features we need in the 5.0 spec, but return a supported version less than + # that. + if(NOT USE_OPENMP_TARGET) + if(NOT DISABLE_OPENMP_TARGET) + # Check the version reported by the compiler + if(OpenMP_CXX_VERSION_MAJOR GREATER_EQUAL 5) + set(USE_OPENMP_TARGET TRUE) + else() + if(OpenMP_CXX_SPEC_DATE GREATER_EQUAL 201811) + # This is the spec date for the 5.0 standard + set(USE_OPENMP_TARGET TRUE) + else() + set(USE_OPENMP_TARGET FALSE) + endif() + endif() + endif() + endif() + # Build up the final list of OpenMP flags + set(omp_opts "") + if(USE_OPENMP_TARGET) + message(STATUS "Enabling support for OpenMP target offload") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "NVHPC") + # We are doing target offload with the NVIDIA compiler + # and need to override the flags. NOTE: The use of "nordc" + # is painful and needed since nvc++ cannot (as of 22.5) build + # standalone shared loadable modules. + #list(APPEND omp_opts -mp=gpu -gpu=nordc -cuda -cudalibs) + list(APPEND omp_opts -mp=gpu) + else() + list(APPEND omp_opts ${OpenMP_CXX_FLAGS}) + endif() + if(OPENMP_TARGET_FLAGS) + # Extra user-specified flags + string(REPLACE " " ";" TARGET_FLAGS_LIST "${OPENMP_TARGET_FLAGS}") + list(APPEND omp_opts ${TARGET_FLAGS_LIST}) + endif() + else() + message(STATUS + "OpenMP target offload disabled. Force on with -DUSE_OPENMP_TARGET=TRUE" + ) + list(APPEND omp_opts ${OpenMP_CXX_FLAGS}) + # Some compilers will forcibly try to offload... + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # FIXME: Only do this for specific gcc versions? In particular, + # older versions don't have this problem. + list(APPEND omp_opts -foffload=disable) + endif() + endif() + set(OpenMP_CXX_FLAGS ${omp_opts}) + string(JOIN " " msg_omp_opts ${omp_opts}) + message(STATUS "Using OpenMP flags: ${msg_omp_opts}") + message(STATUS "Using OpenMP flags (as a list): ${OpenMP_CXX_FLAGS}") +endif() if(TOAST_STATIC_DEPS) set(BLA_STATIC TRUE) set(FFTW_USE_STATIC_LIBS TRUE) set(AATM_USE_STATIC_LIBS TRUE) set(SUITESPARSE_USE_STATIC_LIBS TRUE) + set(FLAC_USE_STATIC_LIBS TRUE) endif() -# First look for MKL, since that will provide both FFT support and BLAS/LAPACK -find_package(MKL) +# First look for MKL and CUDA, since those will provide both +# FFT support and BLAS/LAPACK. + +# CUDA. In some cases, the CUDA toolkit is available (and will be detected) even +# if we want to build without it. Force the user to request using CUDA. +if(USE_CUDA) + find_package(CUDAToolkit) +endif() + +if(USE_MKL) + find_package(MKL) +endif() if(MKL_FOUND) # Use MKL for BLAS / LAPACK @@ -73,10 +151,15 @@ if(MKL_FOUND) set(BLAS_FOUND TRUE) set(LAPACK_FOUND TRUE) else() - # Search for FFTW instead - find_package(FFTW) - if(NOT FFTW_FOUND) - message(FATAL_ERROR "Could not find a supported FFT library (MKL or FFTW)") + if(CUDAToolkit_FOUND) + # This provides FFT support + message(STATUS "Using CUDA FFT") + else() + # Search for FFTW instead + find_package(FFTW) + if(NOT FFTW_FOUND) + message(FATAL_ERROR "Could not find a supported FFT library (MKL, cuFFT or FFTW)") + endif() endif() find_package(BLAS) find_package(LAPACK) @@ -100,10 +183,49 @@ find_package(AATM) find_package(SuiteSparse) -find_package(PythonInterp REQUIRED) +# We require libFLAC >= 1.4.0 for 32bit integer support +set(USE_FLAC FALSE) +if(DISABLE_FLAC) + message(STATUS "FLAC support disabled") +else() + find_package(FLAC) + if(FLAC_FOUND) + if(DEFINED FLAC_VERSION) + if(FLAC_VERSION STREQUAL "") + message(STATUS "Cannot determine FLAC version- assuming it is >= 1.4.0") + set(USE_FLAC TRUE) + else() + string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\..*" "\\1" + FLAC_MAJ_VERSION "${FLAC_VERSION}") + string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\..*" "\\1" + FLAC_MIN_VERSION "${FLAC_VERSION}") + if(FLAC_MAJ_VERSION GREATER 1) + # Future proofing + message(STATUS + "Found FLAC version ${FLAC_VERSION}, enabling support") + set(USE_FLAC TRUE) + else() + if(FLAC_MIN_VERSION GREATER_EQUAL 4) + message(STATUS + "Found FLAC version ${FLAC_VERSION}, enabling support") + set(USE_FLAC TRUE) + endif() + endif() + endif() + else() + message(STATUS "Cannot determine FLAC version- assuming it is >= 1.4.0") + set(USE_FLAC TRUE) + endif() + endif() + if(NOT USE_FLAC) + message(STATUS "Did not find FLAC >= 1.4.0") + endif() +endif() + +find_package(Python3 3.9 COMPONENTS Interpreter Development.Module REQUIRED) # Internal products enable_testing() add_subdirectory(src) -add_subdirectory(pipelines) +add_subdirectory(workflows) diff --git a/MANIFEST.in b/MANIFEST.in index fad193196..031db2483 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,13 +2,15 @@ include README.md include AUTHORS include LICENSE include CMakeLists.txt +recursive-include cmake * recursive-include src * -recursive-include pipelines * recursive-include tutorial * recursive-include examples * -prune examples/job* -prune examples/data recursive-include platforms * -recursive-include cmake * recursive-include docs * +recursive-include etc * +recursive-include wheels * +recursive-include workflows * +recursive-exclude toast __pycache__ prune docs/_build +recursive-include toast/aux * diff --git a/README.md b/README.md index 0bc6610e1..5099e5fa2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Time Ordered Astrophysics Scalable Tools -![Build Status](https://github.com/hpc4cmb/toast/workflows/Run%20Test%20Suite/badge.svg?branch=master) +![Build Status](https://github.com/hpc4cmb/toast/workflows/Run%20Test%20Suite/badge.svg?branch=toast3) [![DOI](https://zenodo.org/badge/33680104.svg)](https://zenodo.org/badge/latestdoi/33680104) @@ -17,4 +17,4 @@ data must often be analyzed simultaneously to extract an estimate of the sky sig See the full documentation here: -https://toast-cmb.readthedocs.io/en/latest/ +https://toast-cmb.readthedocs.io/en/toast3/ diff --git a/cmake/FindCUDAToolkit.cmake b/cmake/FindCUDAToolkit.cmake new file mode 100644 index 000000000..501f2730d --- /dev/null +++ b/cmake/FindCUDAToolkit.cmake @@ -0,0 +1,994 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindCUDAToolkit +--------------- + +.. versionadded:: 3.17 + +This script locates the NVIDIA CUDA toolkit and the associated libraries, but +does not require the ``CUDA`` language be enabled for a given project. This +module does not search for the NVIDIA CUDA Samples. + +.. versionadded:: 3.19 + QNX support. + +Search Behavior +^^^^^^^^^^^^^^^ + +The CUDA Toolkit search behavior uses the following order: + +1. If the ``CUDA`` language has been enabled we will use the directory + containing the compiler as the first search location for ``nvcc``. + +2. If the ``CUDAToolkit_ROOT`` cmake configuration variable (e.g., + ``-DCUDAToolkit_ROOT=/some/path``) *or* environment variable is defined, it + will be searched. If both an environment variable **and** a + configuration variable are specified, the *configuration* variable takes + precedence. + + The directory specified here must be such that the executable ``nvcc`` or + the appropriate ``version.txt`` file can be found underneath the specified + directory. + +3. If the CUDA_PATH environment variable is defined, it will be searched + for ``nvcc``. + +4. The user's path is searched for ``nvcc`` using :command:`find_program`. If + this is found, no subsequent search attempts are performed. Users are + responsible for ensuring that the first ``nvcc`` to show up in the path is + the desired path in the event that multiple CUDA Toolkits are installed. + +5. On Unix systems, if the symbolic link ``/usr/local/cuda`` exists, this is + used. No subsequent search attempts are performed. No default symbolic link + location exists for the Windows platform. + +6. The platform specific default install locations are searched. If exactly one + candidate is found, this is used. The default CUDA Toolkit install locations + searched are: + + +-------------+-------------------------------------------------------------+ + | Platform | Search Pattern | + +=============+=============================================================+ + | macOS | ``/Developer/NVIDIA/CUDA-X.Y`` | + +-------------+-------------------------------------------------------------+ + | Other Unix | ``/usr/local/cuda-X.Y`` | + +-------------+-------------------------------------------------------------+ + | Windows | ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y`` | + +-------------+-------------------------------------------------------------+ + + Where ``X.Y`` would be a specific version of the CUDA Toolkit, such as + ``/usr/local/cuda-9.0`` or + ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0`` + + .. note:: + + When multiple CUDA Toolkits are installed in the default location of a + system (e.g., both ``/usr/local/cuda-9.0`` and ``/usr/local/cuda-10.0`` + exist but the ``/usr/local/cuda`` symbolic link does **not** exist), this + package is marked as **not** found. + + There are too many factors involved in making an automatic decision in + the presence of multiple CUDA Toolkits being installed. In this + situation, users are encouraged to either (1) set ``CUDAToolkit_ROOT`` or + (2) ensure that the correct ``nvcc`` executable shows up in ``$PATH`` for + :command:`find_program` to find. + +Arguments +^^^^^^^^^ + +``[]`` + The ``[]`` argument requests a version with which the package found + should be compatible. See :ref:`find_package version format ` + for more details. + +Options +^^^^^^^ + +``REQUIRED`` + If specified, configuration will error if a suitable CUDA Toolkit is not + found. + +``QUIET`` + If specified, the search for a suitable CUDA Toolkit will not produce any + messages. + +``EXACT`` + If specified, the CUDA Toolkit is considered found only if the exact + ``VERSION`` specified is recovered. + +Imported targets +^^^^^^^^^^^^^^^^ + +An :ref:`imported target ` named ``CUDA::toolkit`` is provided. + +This module defines :prop_tgt:`IMPORTED` targets for each +of the following libraries that are part of the CUDAToolkit: + +- :ref:`CUDA Runtime Library` +- :ref:`CUDA Driver Library` +- :ref:`cuBLAS` +- :ref:`cuFFT` +- :ref:`cuRAND` +- :ref:`cuSOLVER` +- :ref:`cuSPARSE` +- :ref:`cuPTI` +- :ref:`NPP` +- :ref:`nvBLAS` +- :ref:`nvGRAPH` +- :ref:`nvJPEG` +- :ref:`nvidia-ML` +- :ref:`nvRTC` +- :ref:`nvToolsExt` +- :ref:`OpenCL` +- :ref:`cuLIBOS` + +.. _`cuda_toolkit_rt_lib`: + +CUDA Runtime Library +"""""""""""""""""""" + +The CUDA Runtime library (cudart) are what most applications will typically +need to link against to make any calls such as `cudaMalloc`, and `cudaFree`. + +Targets Created: + +- ``CUDA::cudart`` +- ``CUDA::cudart_static`` + +.. _`cuda_toolkit_driver_lib`: + +CUDA Driver Library +"""""""""""""""""""" + +The CUDA Driver library (cuda) are used by applications that use calls +such as `cuMemAlloc`, and `cuMemFree`. This is generally used by advanced + + +Targets Created: + +- ``CUDA::cuda_driver`` +- ``CUDA::cuda_driver`` + +.. _`cuda_toolkit_cuBLAS`: + +cuBLAS +"""""" + +The `cuBLAS `_ library. + +Targets Created: + +- ``CUDA::cublas`` +- ``CUDA::cublas_static`` +- ``CUDA::cublasLt`` starting in CUDA 10.1 +- ``CUDA::cublasLt_static`` starting in CUDA 10.1 + +.. _`cuda_toolkit_cuFFT`: + +cuFFT +""""" + +The `cuFFT `_ library. + +Targets Created: + +- ``CUDA::cufft`` +- ``CUDA::cufftw`` +- ``CUDA::cufft_static`` +- ``CUDA::cufftw_static`` + +cuRAND +"""""" + +The `cuRAND `_ library. + +Targets Created: + +- ``CUDA::curand`` +- ``CUDA::curand_static`` + +.. _`cuda_toolkit_cuSOLVER`: + +cuSOLVER +"""""""" + +The `cuSOLVER `_ library. + +Targets Created: + +- ``CUDA::cusolver`` +- ``CUDA::cusolver_static`` + +.. _`cuda_toolkit_cuSPARSE`: + +cuSPARSE +"""""""" + +The `cuSPARSE `_ library. + +Targets Created: + +- ``CUDA::cusparse`` +- ``CUDA::cusparse_static`` + +.. _`cuda_toolkit_cupti`: + +cupti +""""" + +The `NVIDIA CUDA Profiling Tools Interface `_. + +Targets Created: + +- ``CUDA::cupti`` +- ``CUDA::cupti_static`` + +.. _`cuda_toolkit_NPP`: + +NPP +""" + +The `NPP `_ libraries. + +Targets Created: + +- `nppc`: + + - ``CUDA::nppc`` + - ``CUDA::nppc_static`` + +- `nppial`: Arithmetic and logical operation functions in `nppi_arithmetic_and_logical_operations.h` + + - ``CUDA::nppial`` + - ``CUDA::nppial_static`` + +- `nppicc`: Color conversion and sampling functions in `nppi_color_conversion.h` + + - ``CUDA::nppicc`` + - ``CUDA::nppicc_static`` + +- `nppicom`: JPEG compression and decompression functions in `nppi_compression_functions.h` + Removed starting in CUDA 11.0, use :ref:`nvJPEG` instead. + + - ``CUDA::nppicom`` + - ``CUDA::nppicom_static`` + +- `nppidei`: Data exchange and initialization functions in `nppi_data_exchange_and_initialization.h` + + - ``CUDA::nppidei`` + - ``CUDA::nppidei_static`` + +- `nppif`: Filtering and computer vision functions in `nppi_filter_functions.h` + + - ``CUDA::nppif`` + - ``CUDA::nppif_static`` + +- `nppig`: Geometry transformation functions found in `nppi_geometry_transforms.h` + + - ``CUDA::nppig`` + - ``CUDA::nppig_static`` + +- `nppim`: Morphological operation functions found in `nppi_morphological_operations.h` + + - ``CUDA::nppim`` + - ``CUDA::nppim_static`` + +- `nppist`: Statistics and linear transform in `nppi_statistics_functions.h` and `nppi_linear_transforms.h` + + - ``CUDA::nppist`` + - ``CUDA::nppist_static`` + +- `nppisu`: Memory support functions in `nppi_support_functions.h` + + - ``CUDA::nppisu`` + - ``CUDA::nppisu_static`` + +- `nppitc`: Threshold and compare operation functions in `nppi_threshold_and_compare_operations.h` + + - ``CUDA::nppitc`` + - ``CUDA::nppitc_static`` + +- `npps`: + + - ``CUDA::npps`` + - ``CUDA::npps_static`` + +.. _`cuda_toolkit_nvBLAS`: + +nvBLAS +"""""" + +The `nvBLAS `_ libraries. +This is a shared library only. + +Targets Created: + +- ``CUDA::nvblas`` + +.. _`cuda_toolkit_nvGRAPH`: + +nvGRAPH +""""""" + +The `nvGRAPH `_ library. +Removed starting in CUDA 11.0 + +Targets Created: + +- ``CUDA::nvgraph`` +- ``CUDA::nvgraph_static`` + + +.. _`cuda_toolkit_nvJPEG`: + +nvJPEG +"""""" + +The `nvJPEG `_ library. +Introduced in CUDA 10. + +Targets Created: + +- ``CUDA::nvjpeg`` +- ``CUDA::nvjpeg_static`` + +.. _`cuda_toolkit_nvRTC`: + +nvRTC +""""" + +The `nvRTC `_ (Runtime Compilation) library. +This is a shared library only. + +Targets Created: + +- ``CUDA::nvrtc`` + +.. _`cuda_toolkit_nvml`: + +nvidia-ML +""""""""" + +The `NVIDIA Management Library `_. +This is a shared library only. + +Targets Created: + +- ``CUDA::nvml`` + +.. _`cuda_toolkit_nvToolsExt`: + +nvToolsExt +"""""""""" + +The `NVIDIA Tools Extension `_. +This is a shared library only. + +Targets Created: + +- ``CUDA::nvToolsExt`` + +.. _`cuda_toolkit_opencl`: + +OpenCL +"""""" + +The `NVIDIA OpenCL Library `_. +This is a shared library only. + +Targets Created: + +- ``CUDA::OpenCL`` + +.. _`cuda_toolkit_cuLIBOS`: + +cuLIBOS +""""""" + +The cuLIBOS library is a backend thread abstraction layer library which is +static only. The ``CUDA::cublas_static``, ``CUDA::cusparse_static``, +``CUDA::cufft_static``, ``CUDA::curand_static``, and (when implemented) NPP +libraries all automatically have this dependency linked. + +Target Created: + +- ``CUDA::culibos`` + +**Note**: direct usage of this target by consumers should not be necessary. + +.. _`cuda_toolkit_cuRAND`: + + + +Result variables +^^^^^^^^^^^^^^^^ + +``CUDAToolkit_FOUND`` + A boolean specifying whether or not the CUDA Toolkit was found. + +``CUDAToolkit_VERSION`` + The exact version of the CUDA Toolkit found (as reported by + ``nvcc --version`` or ``version.txt``). + +``CUDAToolkit_VERSION_MAJOR`` + The major version of the CUDA Toolkit. + +``CUDAToolkit_VERSION_MINOR`` + The minor version of the CUDA Toolkit. + +``CUDAToolkit_VERSION_PATCH`` + The patch version of the CUDA Toolkit. + +``CUDAToolkit_BIN_DIR`` + The path to the CUDA Toolkit library directory that contains the CUDA + executable ``nvcc``. + +``CUDAToolkit_INCLUDE_DIRS`` + The path to the CUDA Toolkit ``include`` folder containing the header files + required to compile a project linking against CUDA. + +``CUDAToolkit_LIBRARY_DIR`` + The path to the CUDA Toolkit library directory that contains the CUDA + Runtime library ``cudart``. + +``CUDAToolkit_LIBRARY_ROOT`` + .. versionadded:: 3.18 + + The path to the CUDA Toolkit directory containing the nvvm directory and + version.txt. + +``CUDAToolkit_TARGET_DIR`` + The path to the CUDA Toolkit directory including the target architecture + when cross-compiling. When not cross-compiling this will be equivalent to + the parent directory of ``CUDAToolkit_BIN_DIR``. + +``CUDAToolkit_NVCC_EXECUTABLE`` + The path to the NVIDIA CUDA compiler ``nvcc``. Note that this path may + **not** be the same as + :variable:`CMAKE_CUDA_COMPILER _COMPILER>`. ``nvcc`` must be + found to determine the CUDA Toolkit version as well as determining other + features of the Toolkit. This variable is set for the convenience of + modules that depend on this one. + + +#]=======================================================================] + +# NOTE: much of this was simply extracted from FindCUDA.cmake. + +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html +# +# Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. +# +# Copyright (c) 2007-2009 +# Scientific Computing and Imaging Institute, University of Utah +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# 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. +# +############################################################################### + +# The toolkit is located during compiler detection for CUDA and stored in CMakeCUDACompiler.cmake as +# CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT. +# We compute the rest based on those here to avoid re-searching and to avoid finding a possibly +# different installation. +if(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT) + set(CUDAToolkit_ROOT_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") + set(CUDAToolkit_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}") + set(CUDAToolkit_BIN_DIR "${CUDAToolkit_ROOT_DIR}/bin") + set(CUDAToolkit_NVCC_EXECUTABLE "${CUDAToolkit_BIN_DIR}/nvcc${CMAKE_EXECUTABLE_SUFFIX}") +else() + + function(_CUDAToolkit_find_root_dir ) + cmake_parse_arguments(arg "" "" "SEARCH_PATHS;FIND_FLAGS" ${ARGN}) + + + if(NOT CUDAToolkit_BIN_DIR) + if(NOT CUDAToolkit_SENTINEL_FILE) + find_program(CUDAToolkit_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${arg_SEARCH_PATHS} + ${arg_FIND_FLAGS} + ) + endif() + + if(NOT CUDAToolkit_NVCC_EXECUTABLE) + find_file(CUDAToolkit_SENTINEL_FILE + NAMES version.txt + PATHS ${arg_SEARCH_PATHS} + NO_DEFAULT_PATH + ) + endif() + + if(EXISTS "${CUDAToolkit_NVCC_EXECUTABLE}") + # If NVCC exists then invoke it to find the toolkit location. + # This allows us to support wrapper scripts (e.g. ccache or colornvcc), CUDA Toolkit, + # NVIDIA HPC SDK, and distro's splayed layouts + execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" + OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT) + if(_CUDA_NVCC_OUT MATCHES "\\#\\$ TOP=([^\r\n]*)") + get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_MATCH_1}/bin" ABSOLUTE) + else() + get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY) + endif() + unset(_CUDA_NVCC_OUT) + + mark_as_advanced(CUDAToolkit_BIN_DIR) + set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE) + endif() + + if(CUDAToolkit_SENTINEL_FILE) + get_filename_component(CUDAToolkit_BIN_DIR ${CUDAToolkit_SENTINEL_FILE} DIRECTORY ABSOLUTE) + set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}/bin") + + set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE) + mark_as_advanced(CUDAToolkit_BIN_DIR) + endif() + endif() + + if(CUDAToolkit_BIN_DIR) + get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE) + set(CUDAToolkit_ROOT_DIR "${CUDAToolkit_ROOT_DIR}" PARENT_SCOPE) + endif() + + endfunction() + + function(_CUDAToolkit_find_version_file result_variable) + # We first check for a non-scattered installation to prefer it over a scattered installation. + if(CUDAToolkit_ROOT AND EXISTS "${CUDAToolkit_ROOT}/version.txt") + set(${result_variable} "${CUDAToolkit_ROOT}/version.txt" PARENT_SCOPE) + elseif(CUDAToolkit_ROOT_DIR AND EXISTS "${CUDAToolkit_ROOT_DIR}/version.txt") + set(${result_variable} "${CUDAToolkit_ROOT_DIR}/version.txt" PARENT_SCOPE) + elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt") + set(${result_variable} "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt" PARENT_SCOPE) + elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt") + set(${result_variable} "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt" PARENT_SCOPE) + endif() + endfunction() + + # For NVCC we can easily deduce the SDK binary directory from the compiler path. + if(CMAKE_CUDA_COMPILER_LOADED AND NOT CUDAToolkit_BIN_DIR AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_CUDA_COMPILER}" DIRECTORY) + set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "") + # Try language provided path first. + _CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_BIN_DIR}" FIND_FLAGS NO_DEFAULT_PATH) + mark_as_advanced(CUDAToolkit_BIN_DIR) + endif() + + # Try user provided path + if(NOT CUDAToolkit_ROOT_DIR AND CUDAToolkit_ROOT) + _CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_ROOT}" FIND_FLAGS PATH_SUFFIXES bin NO_DEFAULT_PATH) + endif() + if(NOT CUDAToolkit_ROOT_DIR) + _CUDAToolkit_find_root_dir(FIND_FLAGS PATHS ENV CUDA_PATH PATH_SUFFIXES bin) + endif() + + # If the user specified CUDAToolkit_ROOT but the toolkit could not be found, this is an error. + if(NOT CUDAToolkit_ROOT_DIR AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT})) + # Declare error messages now, print later depending on find_package args. + set(fail_base "Could not find nvcc executable in path specified by") + set(cuda_root_fail "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}") + set(env_cuda_root_fail "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}") + + if(CUDAToolkit_FIND_REQUIRED) + if(DEFINED CUDAToolkit_ROOT) + message(FATAL_ERROR ${cuda_root_fail}) + elseif(DEFINED ENV{CUDAToolkit_ROOT}) + message(FATAL_ERROR ${env_cuda_root_fail}) + endif() + else() + if(NOT CUDAToolkit_FIND_QUIETLY) + if(DEFINED CUDAToolkit_ROOT) + message(STATUS ${cuda_root_fail}) + elseif(DEFINED ENV{CUDAToolkit_ROOT}) + message(STATUS ${env_cuda_root_fail}) + endif() + endif() + set(CUDAToolkit_FOUND FALSE) + unset(fail_base) + unset(cuda_root_fail) + unset(env_cuda_root_fail) + return() + endif() + endif() + + # CUDAToolkit_ROOT cmake / env variable not specified, try platform defaults. + # + # - Linux: /usr/local/cuda-X.Y + # - macOS: /Developer/NVIDIA/CUDA-X.Y + # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y + # + # We will also search the default symlink location /usr/local/cuda first since + # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked + # directory is the desired location. + if(NOT CUDAToolkit_ROOT_DIR) + if(UNIX) + if(NOT APPLE) + set(platform_base "/usr/local/cuda-") + else() + set(platform_base "/Developer/NVIDIA/CUDA-") + endif() + else() + set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v") + endif() + + # Build out a descending list of possible cuda installations, e.g. + file(GLOB possible_paths "${platform_base}*") + # Iterate the glob results and create a descending list. + set(versions) + foreach(p ${possible_paths}) + # Extract version number from end of string + string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p}) + if(IS_DIRECTORY ${p} AND p_version) + list(APPEND versions ${p_version}) + endif() + endforeach() + + # Sort numerically in descending order, so we try the newest versions first. + list(SORT versions COMPARE NATURAL ORDER DESCENDING) + + # With a descending list of versions, populate possible paths to search. + set(search_paths) + foreach(v ${versions}) + list(APPEND search_paths "${platform_base}${v}") + endforeach() + + # Force the global default /usr/local/cuda to the front on Unix. + if(UNIX) + list(INSERT search_paths 0 "/usr/local/cuda") + endif() + + # Now search for the toolkit again using the platform default search paths. + _CUDAToolkit_find_root_dir(SEARCH_PATHS "${search_paths}" FIND_FLAGS PATH_SUFFIXES bin) + + # We are done with these variables now, cleanup for caller. + unset(platform_base) + unset(possible_paths) + unset(versions) + unset(search_paths) + + if(NOT CUDAToolkit_ROOT_DIR) + if(CUDAToolkit_FIND_REQUIRED) + message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.") + elseif(NOT CUDAToolkit_FIND_QUIETLY) + message(STATUS "Could not find nvcc, please set CUDAToolkit_ROOT.") + endif() + + set(CUDAToolkit_FOUND FALSE) + return() + endif() + endif() + + _CUDAToolkit_find_version_file( _CUDAToolkit_version_file ) + if(_CUDAToolkit_version_file) + # CUDAToolkit_LIBRARY_ROOT contains the device library and version file. + get_filename_component(CUDAToolkit_LIBRARY_ROOT "${_CUDAToolkit_version_file}" DIRECTORY ABSOLUTE) + endif() + unset(_CUDAToolkit_version_file) +endif() + +# Find target directory when crosscompiling. +if(CMAKE_CROSSCOMPILING) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a") + # Support for NVPACK + set(CUDAToolkit_TARGET_NAME "armv7-linux-androideabi") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(CUDAToolkit_TARGET_NAME "armv7-linux-gnueabihf") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + if(ANDROID_ARCH_NAME STREQUAL "arm64") + set(CUDAToolkit_TARGET_NAME "aarch64-linux-androideabi") + elseif (CMAKE_SYSTEM_NAME STREQUAL "QNX") + set(CUDAToolkit_TARGET_NAME "aarch64-qnx") + else() + set(CUDAToolkit_TARGET_NAME "aarch64-linux") + endif(ANDROID_ARCH_NAME STREQUAL "arm64") + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(CUDAToolkit_TARGET_NAME "x86_64-linux") + endif() + + if(EXISTS "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}") + set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}") + # add known CUDA target root path to the set of directories we search for programs, libraries and headers + list(PREPEND CMAKE_FIND_ROOT_PATH "${CUDAToolkit_TARGET_DIR}") + + # Mark that we need to pop the root search path changes after we have + # found all cuda libraries so that searches for our cross-compilation + # libraries work when another cuda sdk is in CMAKE_PREFIX_PATH or + # PATh + set(_CUDAToolkit_Pop_ROOT_PATH True) + endif() +endif() + +# If not already set we can simply use the toolkit root or it's a scattered installation. +if(NOT CUDAToolkit_TARGET_DIR) + # Not cross compiling + set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}") + # Now that we have the real ROOT_DIR, find components inside it. + list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR}) + + # Mark that we need to pop the prefix path changes after we have + # found the cudart library. + set(_CUDAToolkit_Pop_Prefix True) +endif() + +# CUDAToolkit_TARGET_DIR always points to the directory containing the include directory. +# On a scattered installation /usr, on a non-scattered something like /usr/local/cuda or /usr/local/cuda-10.2/targets/aarch64-linux. +if(EXISTS "${CUDAToolkit_TARGET_DIR}/include/cuda_runtime.h") + set(CUDAToolkit_INCLUDE_DIR "${CUDAToolkit_TARGET_DIR}/include") +elseif(NOT CUDAToolkit_FIND_QUIETLY) + message(STATUS "Unable to find cuda_runtime.h in \"${CUDAToolkit_TARGET_DIR}/include\" for CUDAToolkit_INCLUDE_DIR.") +endif() + +# The NVHPC layout moves math library headers and libraries to a sibling directory. +# Create a separate variable so this directory can be selectively added to math targets. +if(NOT EXISTS "${CUDAToolkit_INCLUDE_DIR}/cublas_v2.h") + set(CUDAToolkit_MATH_DIR "${CUDAToolkit_TARGET_DIR}/../../math_libs") + set(CUDAToolkit_MATH_INCLUDE_DIR "${CUDAToolkit_TARGET_DIR}/../../math_libs/include") + cmake_path(NORMAL_PATH CUDAToolkit_MATH_INCLUDE_DIR) + if(NOT EXISTS "${CUDAToolkit_MATH_INCLUDE_DIR}/cublas_v2.h") + if(NOT CUDAToolkit_FIND_QUIETLY) + message(STATUS "Unable to find cublas_v2.h in either \"${CUDAToolkit_INCLUDE_DIR}\" or \"${CUDAToolkit_MATH_INCLUDE_DIR}\"") + endif() + unset(CUDAToolkit_MATH_INCLUDE_DIR) + endif() +endif() + +if(CUDAToolkit_NVCC_EXECUTABLE AND + CMAKE_CUDA_COMPILER_VERSION AND + CUDAToolkit_NVCC_EXECUTABLE STREQUAL CMAKE_CUDA_COMPILER) + # Need to set these based off the already computed CMAKE_CUDA_COMPILER_VERSION value + # This if statement will always match, but is used to provide variables for MATCH 1,2,3... + if(CMAKE_CUDA_COMPILER_VERSION MATCHES [=[([0-9]+)\.([0-9]+)\.([0-9]+)]=]) + set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}") + set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}") + set(CUDAToolkit_VERSION "${CMAKE_CUDA_COMPILER_VERSION}") + endif() +elseif(CUDAToolkit_NVCC_EXECUTABLE) + # Compute the version by invoking nvcc + execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT) + if(NVCC_OUT MATCHES [=[ V([0-9]+)\.([0-9]+)\.([0-9]+)]=]) + set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}") + set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}") + set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + endif() + unset(NVCC_OUT) +else() + _CUDAToolkit_find_version_file(version_file) + if(version_file) + file(READ "${version_file}" VERSION_INFO) + if(VERSION_INFO MATCHES [=[CUDA Version ([0-9]+)\.([0-9]+)\.([0-9]+)]=]) + set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}") + set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}") + set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + endif() + endif() +endif() + +# Find the CUDA Runtime Library libcudart +find_library(CUDA_CUDART + NAMES cudart + PATH_SUFFIXES lib64 lib/x64 +) +find_library(CUDA_CUDART + NAMES cudart + PATH_SUFFIXES lib64/stubs lib/x64/stubs +) + +if(NOT CUDA_CUDART AND NOT CUDAToolkit_FIND_QUIETLY) + message(STATUS "Unable to find cudart library.") +endif() + +if(_CUDAToolkit_Pop_Prefix) + list(REMOVE_AT CMAKE_PREFIX_PATH -1) + unset(_CUDAToolkit_Pop_Prefix) +endif() + +#----------------------------------------------------------------------------- +# Perform version comparison and validate all required variables are set. +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(CUDAToolkit + REQUIRED_VARS + CUDAToolkit_INCLUDE_DIR + CUDA_CUDART + CUDAToolkit_BIN_DIR + VERSION_VAR + CUDAToolkit_VERSION +) + +unset(CUDAToolkit_ROOT_DIR) +mark_as_advanced(CUDA_CUDART + CUDAToolkit_INCLUDE_DIR + CUDAToolkit_NVCC_EXECUTABLE + CUDAToolkit_SENTINEL_FILE + ) + +#----------------------------------------------------------------------------- +# Construct result variables +if(CUDAToolkit_FOUND) + set(CUDAToolkit_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIR}) + get_filename_component(CUDAToolkit_LIBRARY_DIR ${CUDA_CUDART} DIRECTORY ABSOLUTE) +endif() + +#----------------------------------------------------------------------------- +# Construct import targets +if(CUDAToolkit_FOUND) + + function(_CUDAToolkit_find_and_add_import_lib lib_name) + cmake_parse_arguments(arg "" "" "ALT;DEPS;EXTRA_PATH_SUFFIXES" ${ARGN}) + + set(search_names ${lib_name} ${arg_ALT}) + + find_library(CUDA_${lib_name}_LIBRARY + NAMES ${search_names} + HINTS ${CUDAToolkit_LIBRARY_DIR} ${CUDAToolkit_MATH_DIR} + ENV CUDA_PATH + PATH_SUFFIXES nvidia/current lib64 lib/x64 lib + ${arg_EXTRA_PATH_SUFFIXES} + ) + # Don't try any stub directories until we have exhausted all other + # search locations. + find_library(CUDA_${lib_name}_LIBRARY + NAMES ${search_names} + HINTS ${CUDAToolkit_LIBRARY_DIR} + ENV CUDA_PATH + PATH_SUFFIXES lib64/stubs lib/x64/stubs lib/stubs stubs + # Support NVHPC splayed math library layout + ../../math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64 + ../../math_libs/lib64 + ) + + mark_as_advanced(CUDA_${lib_name}_LIBRARY) + + if (NOT TARGET CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY) + add_library(CUDA::${lib_name} UNKNOWN IMPORTED) + target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}") + if(DEFINED CUDAToolkit_MATH_INCLUDE_DIR) + string(FIND ${CUDA_${lib_name}_LIBRARY} "math_libs" math_libs) + if(NOT ${math_libs} EQUAL -1) + target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_MATH_INCLUDE_DIR}") + endif() + endif() + set_property(TARGET CUDA::${lib_name} PROPERTY IMPORTED_LOCATION "${CUDA_${lib_name}_LIBRARY}") + foreach(dep ${arg_DEPS}) + if(TARGET CUDA::${dep}) + target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep}) + endif() + endforeach() + endif() + endfunction() + + if(NOT TARGET CUDA::toolkit) + add_library(CUDA::toolkit IMPORTED INTERFACE) + target_include_directories(CUDA::toolkit SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}") + target_link_directories(CUDA::toolkit INTERFACE "${CUDAToolkit_LIBRARY_DIR}") + endif() + + _CUDAToolkit_find_and_add_import_lib(cuda_driver ALT cuda) + + _CUDAToolkit_find_and_add_import_lib(cudart) + _CUDAToolkit_find_and_add_import_lib(cudart_static) + + # setup dependencies that are required for cudart_static when building + # on linux. These are generally only required when using the CUDA toolkit + # when CUDA language is disabled + if(NOT TARGET CUDA::cudart_static_deps + AND TARGET CUDA::cudart_static) + + add_library(CUDA::cudart_static_deps IMPORTED INTERFACE) + target_link_libraries(CUDA::cudart_static INTERFACE CUDA::cudart_static_deps) + + if(UNIX AND (CMAKE_C_COMPILER OR CMAKE_CXX_COMPILER)) + find_package(Threads REQUIRED) + target_link_libraries(CUDA::cudart_static_deps INTERFACE Threads::Threads ${CMAKE_DL_LIBS}) + endif() + + if(UNIX AND NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "QNX")) + # On Linux, you must link against librt when using the static cuda runtime. + find_library(CUDAToolkit_rt_LIBRARY rt) + mark_as_advanced(CUDAToolkit_rt_LIBRARY) + if(NOT CUDAToolkit_rt_LIBRARY) + message(WARNING "Could not find librt library, needed by CUDA::cudart_static") + else() + target_link_libraries(CUDA::cudart_static_deps INTERFACE ${CUDAToolkit_rt_LIBRARY}) + endif() + endif() + endif() + + _CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library + foreach (cuda_lib cublasLt cublas cufft curand cusparse nppc nvjpeg) + _CUDAToolkit_find_and_add_import_lib(${cuda_lib}) + _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos) + endforeach() + + # cuFFTW depends on cuFFT + _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft) + _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft_static) + + # cuSOLVER depends on cuBLAS, and cuSPARSE + _CUDAToolkit_find_and_add_import_lib(cusolver DEPS cublas cusparse) + _CUDAToolkit_find_and_add_import_lib(cusolver_static DEPS cublas_static cusparse_static culibos) + + + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.1.2) + # cusolver depends on liblapack_static.a starting with CUDA 10.1 update 2, + # https://docs.nvidia.com/cuda/archive/11.5.0/cusolver/index.html#static-link-lapack + _CUDAToolkit_find_and_add_import_lib(cusolver_lapack_static ALT lapack_static) # implementation detail static lib + _CUDAToolkit_find_and_add_import_lib(cusolver_static DEPS cusolver_lapack_static) + endif() + + if(CUDAToolkit_VERSION VERSION_GREATER 11.2.1) + # cusolver depends on libcusolver_metis and cublasLt + # https://docs.nvidia.com/cuda/archive/11.2.2/cusolver/index.html#link-dependency + _CUDAToolkit_find_and_add_import_lib(cusolver DEPS cublasLt) + + _CUDAToolkit_find_and_add_import_lib(cusolver_metis_static ALT metis_static) # implementation detail static lib + _CUDAToolkit_find_and_add_import_lib(cusolver_static DEPS cusolver_metis_static cublasLt_static) + endif() + + # nvGRAPH depends on cuRAND, and cuSOLVER. + _CUDAToolkit_find_and_add_import_lib(nvgraph DEPS curand cusolver) + _CUDAToolkit_find_and_add_import_lib(nvgraph_static DEPS curand_static cusolver_static) + + # Process the majority of the NPP libraries. + foreach (cuda_lib nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu) + _CUDAToolkit_find_and_add_import_lib(${cuda_lib} DEPS nppc) + _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS nppc_static) + endforeach() + + _CUDAToolkit_find_and_add_import_lib(cupti + EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ + ../extras/CUPTI/lib/) + _CUDAToolkit_find_and_add_import_lib(cupti_static + EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ + ../extras/CUPTI/lib/) + + _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS cuda_driver) + + _CUDAToolkit_find_and_add_import_lib(nvml ALT nvidia-ml nvml) + + if(WIN32) + # nvtools can be installed outside the CUDA toolkit directory + # so prefer the NVTOOLSEXT_PATH windows only environment variable + # In addition on windows the most common name is nvToolsExt64_1 + find_library(CUDA_nvToolsExt_LIBRARY + NAMES nvToolsExt64_1 nvToolsExt64 nvToolsExt + PATHS ENV NVTOOLSEXT_PATH + ENV CUDA_PATH + PATH_SUFFIXES lib/x64 lib + ) + endif() + _CUDAToolkit_find_and_add_import_lib(nvToolsExt ALT nvToolsExt64) + + _CUDAToolkit_find_and_add_import_lib(OpenCL) +endif() + +if(_CUDAToolkit_Pop_ROOT_PATH) + list(REMOVE_AT CMAKE_FIND_ROOT_PATH 0) + unset(_CUDAToolkit_Pop_ROOT_PATH) +endif() diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index f1391da41..6c675a8c1 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -65,7 +65,7 @@ if( FFTW_ROOT ) FFTW_DOUBLE_LIB NAMES "fftw3" libfftw3-3 PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) @@ -73,23 +73,23 @@ if( FFTW_ROOT ) FFTW_DOUBLE_THREADS_LIB NAMES "fftw3_threads" PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) find_library( - FFTW_DOUBLE_OPENMP_LIB - NAMES "fftw3_omp" - PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" - NO_DEFAULT_PATH + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" + NO_DEFAULT_PATH ) find_library( FFTW_FLOAT_LIB NAMES "fftw3f" libfftw3f-3 PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) @@ -97,23 +97,23 @@ if( FFTW_ROOT ) FFTW_FLOAT_THREADS_LIB NAMES "fftw3f_threads" PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) find_library( - FFTW_FLOAT_OPENMP_LIB - NAMES "fftw3f_omp" - PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" - NO_DEFAULT_PATH + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" + NO_DEFAULT_PATH ) find_library( FFTW_LONGDOUBLE_LIB NAMES "fftw3l" libfftw3l-3 PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) @@ -121,16 +121,16 @@ if( FFTW_ROOT ) FFTW_LONGDOUBLE_THREADS_LIB NAMES "fftw3l_threads" PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" NO_DEFAULT_PATH ) find_library( - FFTW_LONGDOUBLE_OPENMP_LIB - NAMES "fftw3l_omp" - PATHS ${FFTW_ROOT} - PATH_SUFFIXES "lib" "lib64" - NO_DEFAULT_PATH + FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftw3l_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" + NO_DEFAULT_PATH ) #find includes @@ -143,62 +143,64 @@ if( FFTW_ROOT ) else() + set(SEARCH_DIRS ${PKG_FFTW_LIBDIR} ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}) + find_library( FFTW_DOUBLE_LIB NAMES "fftw3" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library( FFTW_DOUBLE_THREADS_LIB NAMES "fftw3_threads" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library( - FFTW_DOUBLE_OPENMP_LIB - NAMES "fftw3_omp" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${SEARCH_DIRS} ) find_library( FFTW_FLOAT_LIB NAMES "fftw3f" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library( FFTW_FLOAT_THREADS_LIB NAMES "fftw3f_threads" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library( - FFTW_FLOAT_OPENMP_LIB - NAMES "fftw3f_omp" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${SEARCH_DIRS} ) find_library( FFTW_LONGDOUBLE_LIB NAMES "fftw3l" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library( FFTW_LONGDOUBLE_THREADS_LIB NAMES "fftw3l_threads" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) find_library(FFTW_LONGDOUBLE_OPENMP_LIB - NAMES "fftw3l_omp" - PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + NAMES "fftw3l_omp" + PATHS ${SEARCH_DIRS} ) find_path(FFTW_INCLUDE_DIRS NAMES "fftw3.h" - PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} + PATHS ${SEARCH_DIRS} ) endif( FFTW_ROOT ) diff --git a/cmake/FindFLAC.cmake b/cmake/FindFLAC.cmake new file mode 100644 index 000000000..d3aced4ab --- /dev/null +++ b/cmake/FindFLAC.cmake @@ -0,0 +1,89 @@ +# Copied without modification from libsndfile +# (https://github.com/libsndfile/libsndfile) +# +# (C) Erik de Castro Lopo +# +# Released under LGPL v2.1 +# https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html +# +# +# - Find FLAC +# Find the native FLAC includes and libraries +# +# FLAC_USE_STATIC_LIBS: Search for static libraries. +# +# FLAC_INCLUDE_DIRS - where to find FLAC headers. +# FLAC_LIBRARIES - List of libraries when using libFLAC. +# FLAC_FOUND - True if libFLAC found. +# FLAC_DEFINITIONS - FLAC compile definitons + +# Check whether to search static or dynamic libs +set(CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES}) + +if(${FLAC_USE_STATIC_LIBS}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) +else() + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV}) +endif() + +if (FLAC_INCLUDE_DIR) + # Already in cache, be silent + set (FLAC_FIND_QUIETLY TRUE) +endif () + +find_package (Ogg QUIET) + +find_package (PkgConfig QUIET) +pkg_check_modules(PC_FLAC QUIET flac) + +set(FLAC_VERSION ${PC_FLAC_VERSION}) + +find_path (FLAC_INCLUDE_DIR FLAC/stream_decoder.h + HINTS + ${PC_FLAC_INCLUDEDIR} + ${PC_FLAC_INCLUDE_DIRS} + ${FLAC_ROOT} + ) + +# MSVC built libraries can name them *_static, which is good as it +# distinguishes import libraries from static libraries with the same extension. +find_library (FLAC_LIBRARY + NAMES + FLAC + libFLAC + libFLAC_dynamic + libFLAC_static + HINTS + ${PC_FLAC_LIBDIR} + ${PC_FLAC_LIBRARY_DIRS} + ${FLAC_ROOT} + ) + +# Handle the QUIETLY and REQUIRED arguments and set FLAC_FOUND to TRUE if +# all listed variables are TRUE. +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FLAC + REQUIRED_VARS + FLAC_LIBRARY + FLAC_INCLUDE_DIR + VERSION_VAR + FLAC_VERSION + ) + +if (FLAC_FOUND) + set (FLAC_INCLUDE_DIRS ${FLAC_INCLUDE_DIR}) + set (FLAC_LIBRARIES ${FLAC_LIBRARY} ${OGG_LIBRARIES}) + if (NOT TARGET FLAC::FLAC) + add_library(FLAC::FLAC UNKNOWN IMPORTED) + set_target_properties(FLAC::FLAC PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}" + IMPORTED_LOCATION "${FLAC_LIBRARY}" + INTERFACE_LINK_LIBRARIES Ogg::ogg + ) + endif () +endif () + +mark_as_advanced(FLAC_INCLUDE_DIR FLAC_LIBRARY) + +# Restore library search suffix +set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV}) diff --git a/cmake/FindLAPACKnames.cmake b/cmake/FindLAPACKnames.cmake index bf4b6c395..f2cc6681b 100644 --- a/cmake/FindLAPACKnames.cmake +++ b/cmake/FindLAPACKnames.cmake @@ -12,19 +12,25 @@ set(MANGLING_OPTIONS "LOWER" "UPPER" "UBACK" - "UFRONT") + "UFRONT" +) set(LAPACK_NAMES "") +set(OMP_BLAS "") +if(OpenMP_C_FOUND) + set(OMP_BLAS "${OpenMP_C_FLAGS}") +endif() + foreach(MANGLING IN LISTS MANGLING_OPTIONS) try_compile(TRY_MANGLING ${CMAKE_BINARY_DIR}/tmpLapack ${CMAKE_MODULE_PATH}/lapack_mangling.cpp CMAKE_FLAGS "${BLAS_LINKER_FLAGS}" "${LAPACK_LINKER_FLAGS}" COMPILE_DEFINITIONS "-DLAPACK_${MANGLING}" - LINK_LIBRARIES "${LAPACK_LIBRARIES}" "${BLAS_LIBRARIES}" + LINK_LIBRARIES "${LAPACK_LIBRARIES}" "${BLAS_LIBRARIES}" "${OMP_BLAS}" OUTPUT_VARIABLE OUTPUT_MANGLING) - #message("Test output for LAPACK_${MANGLING}:") - #message(${OUTPUT_MANGLING}) + # message("Test output for LAPACK_${MANGLING}:") + # message(${OUTPUT_MANGLING}) if(TRY_MANGLING) set(LAPACK_NAMES "${MANGLING}") break() diff --git a/cmake/FindPackageHandleStandardArgs.cmake b/cmake/FindPackageHandleStandardArgs.cmake new file mode 100644 index 000000000..fbcf7cd88 --- /dev/null +++ b/cmake/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,605 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPackageHandleStandardArgs +----------------------------- + +This module provides functions intended to be used in :ref:`Find Modules` +implementing :command:`find_package()` calls. + +.. command:: find_package_handle_standard_args + + This command handles the ``REQUIRED``, ``QUIET`` and version-related + arguments of :command:`find_package`. It also sets the + ``_FOUND`` variable. The package is considered found if all + variables listed contain valid results, e.g. valid filepaths. + + There are two signatures: + + .. code-block:: cmake + + find_package_handle_standard_args( + (DEFAULT_MSG|) + ... + ) + + find_package_handle_standard_args( + [FOUND_VAR ] + [REQUIRED_VARS ...] + [VERSION_VAR ] + [HANDLE_VERSION_RANGE] + [HANDLE_COMPONENTS] + [CONFIG_MODE] + [NAME_MISMATCHED] + [REASON_FAILURE_MESSAGE ] + [FAIL_MESSAGE ] + ) + + The ``_FOUND`` variable will be set to ``TRUE`` if all + the variables ``...`` are valid and any optional + constraints are satisfied, and ``FALSE`` otherwise. A success or + failure message may be displayed based on the results and on + whether the ``REQUIRED`` and/or ``QUIET`` option was given to + the :command:`find_package` call. + + The options are: + + ``(DEFAULT_MSG|)`` + In the simple signature this specifies the failure message. + Use ``DEFAULT_MSG`` to ask for a default message to be computed + (recommended). Not valid in the full signature. + + ``FOUND_VAR `` + .. deprecated:: 3.3 + + Specifies either ``_FOUND`` or + ``_FOUND`` as the result variable. This exists only + for compatibility with older versions of CMake and is now ignored. + Result variables of both names are always set for compatibility. + + ``REQUIRED_VARS ...`` + Specify the variables which are required for this package. + These may be named in the generated failure message asking the + user to set the missing variable values. Therefore these should + typically be cache entries such as ``FOO_LIBRARY`` and not output + variables like ``FOO_LIBRARIES``. + + .. versionchanged:: 3.18 + If ``HANDLE_COMPONENTS`` is specified, this option can be omitted. + + ``VERSION_VAR `` + Specify the name of a variable that holds the version of the package + that has been found. This version will be checked against the + (potentially) specified required version given to the + :command:`find_package` call, including its ``EXACT`` option. + The default messages include information about the required + version and the version which has been actually found, both + if the version is ok or not. + + ``HANDLE_VERSION_RANGE`` + .. versionadded:: 3.19 + + Enable handling of a version range, if one is specified. Without this + option, a developer warning will be displayed if a version range is + specified. + + ``HANDLE_COMPONENTS`` + Enable handling of package components. In this case, the command + will report which components have been found and which are missing, + and the ``_FOUND`` variable will be set to ``FALSE`` + if any of the required components (i.e. not the ones listed after + the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are + missing. + + ``CONFIG_MODE`` + Specify that the calling find module is a wrapper around a + call to ``find_package( NO_MODULE)``. This implies + a ``VERSION_VAR`` value of ``_VERSION``. The command + will automatically check whether the package configuration file + was found. + + ``REASON_FAILURE_MESSAGE `` + .. versionadded:: 3.16 + + Specify a custom message of the reason for the failure which will be + appended to the default generated message. + + ``FAIL_MESSAGE `` + Specify a custom failure message instead of using the default + generated message. Not recommended. + + ``NAME_MISMATCHED`` + .. versionadded:: 3.17 + + Indicate that the ```` does not match + ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a + warning, but it may be intentional for usage of the command for components + of a larger package. + +Example for the simple signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibXml2 DEFAULT_MSG + LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) + +The ``LibXml2`` package is considered to be found if both +``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid. +Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found +and ``REQUIRED`` was used, it fails with a +:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was +used or not. If it is found, success will be reported, including +the content of the first ````. On repeated CMake runs, +the same message will not be printed again. + +.. note:: + + If ```` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the + calling module, a warning that there is a mismatch is given. The + ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using + the old signature and the ``NAME_MISMATCHED`` argument using the new + signature. To avoid forcing the caller to require newer versions of CMake for + usage, the variable's value will be used if defined when the + ``NAME_MISMATCHED`` argument is not passed for the new signature (but using + both is an error).. + +Example for the full signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibArchive + REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR + VERSION_VAR LibArchive_VERSION) + +In this case, the ``LibArchive`` package is considered to be found if +both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid. +Also the version of ``LibArchive`` will be checked by using the version +contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given, +the default messages will be printed. + +Another example for the full signature: + +.. code-block:: cmake + + find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) + find_package_handle_standard_args(Automoc4 CONFIG_MODE) + +In this case, a ``FindAutmoc4.cmake`` module wraps a call to +``find_package(Automoc4 NO_MODULE)`` and adds an additional search +directory for ``automoc4``. Then the call to +``find_package_handle_standard_args`` produces a proper success/failure +message. + +.. command:: find_package_check_version + + .. versionadded:: 3.19 + + Helper function which can be used to check if a ```` is valid + against version-related arguments of :command:`find_package`. + + .. code-block:: cmake + + find_package_check_version( + [HANDLE_VERSION_RANGE] + [RESULT_MESSAGE_VARIABLE ] + ) + + The ```` will hold a boolean value giving the result of the check. + + The options are: + + ``HANDLE_VERSION_RANGE`` + Enable handling of a version range, if one is specified. Without this + option, a developer warning will be displayed if a version range is + specified. + + ``RESULT_MESSAGE_VARIABLE `` + Specify a variable to get back a message describing the result of the check. + +Example for the usage: + +.. code-block:: cmake + + find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE + RESULT_MESSAGE_VARIABLE reason) + if (result) + message (STATUS "${reason}") + else() + message (FATAL_ERROR "${reason}") + endif() +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) + + +cmake_policy(PUSH) +# numbers and boolean constants +cmake_policy (SET CMP0012 NEW) +# IN_LIST operator +cmake_policy (SET CMP0057 NEW) + + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + set (__msg "${_msg}") + if (FPHSA_REASON_FAILURE_MESSAGE) + string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") + endif() + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${__msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${__msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + string(APPEND configsText "\n ${filename} (version ${version})") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + if (FPHSA_REASON_FAILURE_MESSAGE) + string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ") + else() + set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}") + endif() + else() + string(APPEND configsText "\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_CHECK_VERSION version result) + cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "") + + if (FPCV_UNPARSED_ARGUMENTS) + message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments") + endif() + if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES) + message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument") + endif() + + set (${result} FALSE PARENT_SCOPE) + if (FPCV_RESULT_MESSAGE_VARIABLE) + unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE) + endif() + + if (_CMAKE_FPHSA_PACKAGE_NAME) + set (package "${_CMAKE_FPHSA_PACKAGE_NAME}") + elseif (CMAKE_FIND_PACKAGE_NAME) + set (package "${CMAKE_FIND_PACKAGE_NAME}") + else() + message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'") + endif() + + if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE + AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE) + message(AUTHOR_WARNING + "`find_package()` specify a version range but the option " + "HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. " + "Only the lower endpoint of the range will be used.") + endif() + + + set (version_ok FALSE) + unset (version_msg) + + if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE) + if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" + AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN) + AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" + AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX) + OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" + AND version VERSION_LESS ${package}_FIND_VERSION_MAX))) + set (version_ok TRUE) + set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")") + else() + set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"") + endif() + elseif (DEFINED ${package}_FIND_VERSION) + if(${package}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" version_dots "${version}") + # add one dot because there is one dot more than there are components + string(LENGTH "${version_dots}." version_dots) + if (version_dots GREATER ${package}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${package}_FIND_VERSION_COUNT EQUAL 1) + set(version_regex "[^.]*") + elseif (${package}_FIND_VERSION_COUNT EQUAL 2) + set(version_regex "[^.]*\\.[^.]*") + elseif (${package}_FIND_VERSION_COUNT EQUAL 3) + set(version_regex "[^.]*\\.[^.]*\\.[^.]*") + else() + set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif() + string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}") + if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head) + set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") + else () + set(version_ok TRUE) + set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")") + endif () + else () + if (NOT ${package}_FIND_VERSION VERSION_EQUAL version) + set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"") + else () + set(version_ok TRUE) + set(version_msg "(found suitable exact version \"${version}\")") + endif () + endif () + else() # minimum version + if (${package}_FIND_VERSION VERSION_GREATER version) + set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"") + else() + set(version_ok TRUE) + set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")") + endif() + endif() + else () + set(version_ok TRUE) + set(version_msg "(found version \"${version}\")") + endif() + + set (${result} ${version_ok} PARENT_SCOPE) + if (FPCV_RESULT_MESSAGE_VARIABLE) + set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE) + endif() +endfunction() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + + # Set up the arguments for `cmake_parse_arguments`. + set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE) + set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + + # Check whether we are in 'simple' or 'extended' mode: + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + unset(FPHSA_NAME_MISMATCHED_override) + if (DEFINED FPHSA_NAME_MISMATCHED) + # If the variable NAME_MISMATCHED variable is set, error if it is passed as + # an argument. The former is for old signatures, the latter is for new + # signatures. + list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx) + if (NOT name_mismatched_idx EQUAL "-1") + message(FATAL_ERROR + "The `NAME_MISMATCHED` argument may only be specified by the argument or " + "the variable, not both.") + endif () + + # But use the variable if it is not an argument to avoid forcing minimum + # CMake version bumps for calling modules. + set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}") + endif () + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + endif() + + if (DEFINED FPHSA_NAME_MISMATCHED_override) + set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}") + endif () + + if (DEFINED CMAKE_FIND_PACKAGE_NAME + AND NOT FPHSA_NAME_MISMATCHED + AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME) + message(AUTHOR_WARNING + "The package name passed to `find_package_handle_standard_args` " + "(${_NAME}) does not match the name of the calling package " + "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling " + "code that expects `find_package` result variables (e.g., `_FOUND`) " + "to follow a certain pattern.") + endif () + + if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE) + message(AUTHOR_WARNING + "`find_package()` specify a version range but the module ${_NAME} does " + "not support this capability. Only the lower endpoint of the range " + "will be used.") + endif() + + # to propagate package name to FIND_PACKAGE_CHECK_VERSION + set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}") + + # now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + if (FPHSA_REQUIRED_VARS) + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + endif() + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND) + set(_FOUND_VAR_MIXED ${_NAME}_FOUND) + if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER) + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + set(FPHSA_FOUND_${_NAME} TRUE) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(FPHSA_FOUND_${_NAME} FALSE) + string(APPEND MISSING_VARS " ${_CURRENT_VAR}") + else() + string(APPEND DETAILS "[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(FPHSA_FOUND_${_NAME}) + set(${_NAME}_FOUND TRUE) + set(${_NAME_UPPER}_FOUND TRUE) + else() + set(${_NAME}_FOUND FALSE) + set(${_NAME_UPPER}_FOUND FALSE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components:") + endif() + string(APPEND FOUND_COMPONENTS_MSG " ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components:") + endif() + string(APPEND MISSING_COMPONENTS_MSG " ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + string(APPEND MISSING_VARS " ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + string(APPEND DETAILS "[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) + if (FPHSA_HANDLE_VERSION_RANGE) + set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE) + else() + set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE) + endif() + find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG + ${FPCV_HANDLE_VERSION_RANGE}) + else() + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE) + set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + endif() + else () + # Check with DEFINED as the found version may be 0. + if(DEFINED ${FPHSA_VERSION_VAR}) + set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")") + endif() + endif () + + if(VERSION_OK) + string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]") + else() + set(${_NAME}_FOUND FALSE) + endif() + + + # print the result: + if (${_NAME}_FOUND) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + set(RESULT_MSG) + if (_FIRST_REQUIRED_VAR) + string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}") + endif() + if (COMPONENT_MSG) + if (RESULT_MSG) + string (APPEND RESULT_MSG ", ") + endif() + string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) + set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) +endfunction() + + +cmake_policy(POP) diff --git a/cmake/FindPackageMessage.cmake b/cmake/FindPackageMessage.cmake new file mode 100644 index 000000000..0628b9816 --- /dev/null +++ b/cmake/FindPackageMessage.cmake @@ -0,0 +1,48 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPackageMessage +------------------ + +.. code-block:: cmake + + find_package_message( "message for user" "find result details") + +This function is intended to be used in FindXXX.cmake modules files. +It will print a message once for each unique find result. This is +useful for telling the user where a package was found. The first +argument specifies the name (XXX) of the package. The second argument +specifies the message to display. The third argument lists details +about the find result so that if they change the message will be +displayed again. The macro also obeys the QUIET argument to the +find_package command. + +Example: + +.. code-block:: cmake + + if(X11_FOUND) + find_package_message(X11 "Found X11: ${X11_X11_LIB}" + "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") + else() + ... + endif() +#]=======================================================================] + +function(find_package_message pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/cmake/FindSuiteSparse.cmake b/cmake/FindSuiteSparse.cmake index a39a9e858..555053d25 100644 --- a/cmake/FindSuiteSparse.cmake +++ b/cmake/FindSuiteSparse.cmake @@ -347,7 +347,7 @@ if (SUITESPARSE_CONFIG_FOUND) # timing by default when compiled on Linux or Unix, but not on OSX (which # does not have librt). if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE) - suitesparse_find_component(LIBRT LIBRARIES rt) + # suitesparse_find_component(LIBRT LIBRARIES rt) if (LIBRT_FOUND) message(STATUS "Adding librt: ${LIBRT_LIBRARY} to " "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if " diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index e35d8850c..000000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index ea5909bef..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/TOAST.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/TOAST.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/TOAST" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/TOAST" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_static/data_dist_1.png b/docs/_static/data_dist_1.png deleted file mode 100644 index 09227aad3..000000000 Binary files a/docs/_static/data_dist_1.png and /dev/null differ diff --git a/docs/_static/data_dist_1.svg b/docs/_static/data_dist_1.svg deleted file mode 100644 index 83ec4da25..000000000 --- a/docs/_static/data_dist_1.svg +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Obs 0 - - Time --> - - - - - - - - - - - - - - - - Obs 1 - Obs 2 - Time --> - Time --> - - P0 - - P1 - - P2 - - P3 - - diff --git a/docs/_static/data_dist_2.png b/docs/_static/data_dist_2.png deleted file mode 100644 index f1516afef..000000000 Binary files a/docs/_static/data_dist_2.png and /dev/null differ diff --git a/docs/_static/data_dist_2.svg b/docs/_static/data_dist_2.svg deleted file mode 100644 index 80fd7f8db..000000000 --- a/docs/_static/data_dist_2.svg +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Obs 0 - - Time --> - - - - - - - - - - - - - - - - Obs 1 - Obs 2 - Time --> - Time --> - - P0 - - P1 - - P2 - - P3 - Group 0 - Group 1 - - diff --git a/docs/_static/data_dist_3.png b/docs/_static/data_dist_3.png deleted file mode 100644 index c9800dead..000000000 Binary files a/docs/_static/data_dist_3.png and /dev/null differ diff --git a/docs/_static/data_dist_3.svg b/docs/_static/data_dist_3.svg deleted file mode 100644 index 96cbc6139..000000000 --- a/docs/_static/data_dist_3.svg +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Obs 0 - - Time --> - - - - - - - - - - - - - - - - Obs 1 - Obs 2 - Time --> - Time --> - - P0 - - P1 - - P2 - - P3 - Group 0 - Group 1 - - diff --git a/docs/_static/data_dist_4.png b/docs/_static/data_dist_4.png deleted file mode 100644 index e3c0b9f4d..000000000 Binary files a/docs/_static/data_dist_4.png and /dev/null differ diff --git a/docs/_static/data_dist_4.svg b/docs/_static/data_dist_4.svg deleted file mode 100644 index 480328998..000000000 --- a/docs/_static/data_dist_4.svg +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Obs 0 - - Time --> - - - - - - - - - - - - - - - - Obs 1 - Obs 2 - Time --> - Time --> - - P0 - - P1 - - P2 - - P3 - Group 0 - Group 1 - "detranks=1" - - - - P0 - P1 - P2 - P2 - P3 - P3 - - diff --git a/docs/_static/data_dist_5.png b/docs/_static/data_dist_5.png deleted file mode 100644 index cb70a59dc..000000000 Binary files a/docs/_static/data_dist_5.png and /dev/null differ diff --git a/docs/_static/data_dist_5.svg b/docs/_static/data_dist_5.svg deleted file mode 100644 index 030a92517..000000000 --- a/docs/_static/data_dist_5.svg +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Obs 0 - - Time --> - - - - - - - - - - - - - - - - Obs 1 - Obs 2 - Time --> - Time --> - - P0 - - P1 - - P2 - - P3 - Group 0 - Group 1 - "detranks=group_size" - - P0 - P1 - P2 - P3 - - P2 - P3 - - - diff --git a/docs/_static/toast_data_dist.png b/docs/_static/toast_data_dist.png deleted file mode 100644 index ac6dc2c1b..000000000 Binary files a/docs/_static/toast_data_dist.png and /dev/null differ diff --git a/docs/_static/toast_data_dist.svg b/docs/_static/toast_data_dist.svg deleted file mode 100644 index f3acf3792..000000000 --- a/docs/_static/toast_data_dist.svg +++ /dev/null @@ -1,985 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - Group 0 - - - - - Group 1 - - - - Group 2 - Group 3 - Obs 0 - - - - - - - - - Time --> - - - - - Obs 1 - - - - - - - - - Time --> - - - - - - - Time --> - Obs 2 - - - - - Obs 3 - - - - - - - - - Time --> - - - - - Obs 4 - - - - - - - - - Time --> - - - - - - - - - - - Time --> - Obs 5 - P00 (0) - P00 (0) - P06 (0) - P12 (0) - P12 (0) - P18 (0) - P01 (1) - P01 (1) - P07 (1) - P13 (1) - P13 (1) - P19 (1) - P02 (2) - P02 (2) - P08 (2) - P14 (2) - P14 (2) - P20 (2) - P03 (3) - P03 (3) - P09 (3) - P15 (3) - P15 (3) - P21 (3) - P04 (4) - P04 (4) - P10 (4) - P16 (4) - P16 (4) - P22 (4) - P23 (5) - P17 (5) - P17 (5) - P11 (5) - P05 (5) - P05 (5) - - diff --git a/docs/build_docs.sh b/docs/build_docs.sh deleted file mode 100755 index 00b2bbf26..000000000 --- a/docs/build_docs.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# Copy the docs directory to the local working directory and build it with sphinx - -set -e - -# Get the absolute path to the docs folder -pushd $(dirname $0) > /dev/null -docdir=$(pwd -P) -popd > /dev/null - -cp -a "${docdir}" ./docs -pushd ./docs > /dev/null -make html -popd > /dev/null diff --git a/docs/changes.rst b/docs/changes.rst deleted file mode 100644 index e79df9fa3..000000000 --- a/docs/changes.rst +++ /dev/null @@ -1,193 +0,0 @@ -.. _changes: - -Change Log -------------------------- - -2.3.13 (Unreleased) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Nothing yet. - -2.3.12 (2020-11-12) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Fix typo in MKL cmake checks which broke OS X builds with MKL. -* Fix typo in toast_ground_schedule.py pipeline. - -2.3.11 (2020-11-12) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Restore support for directly using Intel MKL for FFTs (PR `#371`_, `#372`_). -* Fixed bug in wind velocity during atmosphere simulations. - -.. _`#371`: https://github.com/hpc4cmb/toast/pull/371 -.. _`#372`: https://github.com/hpc4cmb/toast/pull/372 - -2.3.10 (2020-10-15) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Run serial unit tests without MPI. Fix bug in ground filter (PR `#370`_). - -.. _`#370`: https://github.com/hpc4cmb/toast/pull/370 - -2.3.9 (2020-10-15) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Add stand-alone benchmarking tool (PR `#365`_). -* Update wheels to use latest OpenBLAS and SuiteSparse (PR `#368`_). -* Tweaks to atmosphere simulation based on calibration campaign (PR `#367`_). -* Add support for 2D polynomial filtering across focalplane (PR `#366`_). -* Ground scheduler support for elevation modulated scans (PR `#364`_). -* Add better dictionary interface to Cache class (PR `#363`_). -* Support simulating basic non-ideal HWP response (PR `#362`_). -* Ground scheduler support for fixed elevations and partial scans (PR `#361`_). -* Additional check for NULL plan returned from FFTW (PR `#360`_). - -.. _`#360`: https://github.com/hpc4cmb/toast/pull/360 -.. _`#361`: https://github.com/hpc4cmb/toast/pull/361 -.. _`#362`: https://github.com/hpc4cmb/toast/pull/362 -.. _`#363`: https://github.com/hpc4cmb/toast/pull/363 -.. _`#364`: https://github.com/hpc4cmb/toast/pull/364 -.. _`#365`: https://github.com/hpc4cmb/toast/pull/365 -.. _`#366`: https://github.com/hpc4cmb/toast/pull/366 -.. _`#367`: https://github.com/hpc4cmb/toast/pull/367 -.. _`#368`: https://github.com/hpc4cmb/toast/pull/368 - -2.3.8 (2020-06-27) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Minor release focusing on build system changes to support packaging -* Update bundled pybind11 and other fixes for wheels and conda packages (PR `#359`_). - -.. _`#359`: https://github.com/hpc4cmb/toast/pull/359 - -2.3.7 (2020-06-13) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Documentation updates and deployment of pip wheels on tags (PR `#356`_). -* Cleanups of conviqt polarization support (PR `#347`_). -* Support elevation nods in ground simulations (PR `#355`_). -* Fix a bug in parallel writing of Healpix FITS files (PR `#354`_). -* Remove dependence on MPI compilers. Only mpi4py is needed (PR `#350`_). -* Use the native mapmaker by default in the example pipelines (PR `#352`_). -* Updates to build system for pip wheel compatibility (PR `#348`_, `#351`_). -* Switch to github actions instead of travis for continuous integration (PR `#349`_). -* Updates to many parts of the simulation and filtering operators (PR `#341`_). -* In the default Healpix pointing matrix, support None for HWP angle (PR `#345`_). -* Add support for HWP in conviqt beam convolution (PR `#343`_). -* Reimplementation of example jobs used for benchmarks (PR `#332`_). -* Apply atmosphere scaling in temperature, not intensity (PR `#328`_). -* Minor bugfix in binner when running in debug mode (PR `#325`_). -* Add optional boresight offset to the scheduler (PR `#329`_). -* Implement helper tools for parsing mapmaker options (PR `#321`_). - -.. _`#356`: https://github.com/hpc4cmb/toast/pull/356 -.. _`#347`: https://github.com/hpc4cmb/toast/pull/347 -.. _`#355`: https://github.com/hpc4cmb/toast/pull/355 -.. _`#354`: https://github.com/hpc4cmb/toast/pull/354 -.. _`#350`: https://github.com/hpc4cmb/toast/pull/350 -.. _`#352`: https://github.com/hpc4cmb/toast/pull/352 -.. _`#351`: https://github.com/hpc4cmb/toast/pull/351 -.. _`#348`: https://github.com/hpc4cmb/toast/pull/348 -.. _`#349`: https://github.com/hpc4cmb/toast/pull/349 -.. _`#341`: https://github.com/hpc4cmb/toast/pull/341 -.. _`#345`: https://github.com/hpc4cmb/toast/pull/345 -.. _`#343`: https://github.com/hpc4cmb/toast/pull/343 -.. _`#332`: https://github.com/hpc4cmb/toast/pull/332 -.. _`#328`: https://github.com/hpc4cmb/toast/pull/328 -.. _`#325`: https://github.com/hpc4cmb/toast/pull/325 -.. _`#329`: https://github.com/hpc4cmb/toast/pull/329 -.. _`#321`: https://github.com/hpc4cmb/toast/pull/321 - -2.3.6 (2020-01-19) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Overhaul documentation (PR `#320`_). -* Small typo fix for conviqt operator (PR `#319`_). -* Support high-cadence ground scan strategies and fix a bug in turnaround simulation (PR `#316`_). -* Fix BLAS / LAPACK name mangling detection (PR `#315`_). -* Allow disabling sky sim in example pipeline (PR `#313`_). - -.. _`#320`: https://github.com/hpc4cmb/toast/pull/320 -.. _`#319`: https://github.com/hpc4cmb/toast/pull/319 -.. _`#316`: https://github.com/hpc4cmb/toast/pull/316 -.. _`#315`: https://github.com/hpc4cmb/toast/pull/315 -.. _`#313`: https://github.com/hpc4cmb/toast/pull/313 - - -2.3.5 (2019-11-19) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Documentation updates (PR `#310`_). - -.. _`#310`: https://github.com/hpc4cmb/toast/pull/310 - - -2.3.4 (2019-11-17) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Disabling timing tests during build of conda package. - - -2.3.3 (2019-11-16) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Change way that the MPI communicator is passed to C++ (PR `#309`_). - -.. _`#309`: https://github.com/hpc4cmb/toast/pull/309 - - -2.3.2 (2019-11-13) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Convert atmosphere simulation to new libaatm package (PR `#307`_). -* Improve vector math unit tests (PR `#296`_). -* Updates to conviqt operator (PR `#304`_). -* Satellite example pipeline cleanups. -* Store local pixel information in the data dictionary (PR `#306`_). -* Add elevation-dependent noise (PR `#303`_). -* Move global / local pixel lookup into compiled code (PR `#302`_). -* PySM operator changes to communicator (PR `#301`_). -* Install documentation updates (PR `#300`_, `#299`_). - -.. _`#307`: https://github.com/hpc4cmb/toast/pull/307 -.. _`#296`: https://github.com/hpc4cmb/toast/pull/296 -.. _`#304`: https://github.com/hpc4cmb/toast/pull/304 -.. _`#306`: https://github.com/hpc4cmb/toast/pull/306 -.. _`#303`: https://github.com/hpc4cmb/toast/pull/303 -.. _`#302`: https://github.com/hpc4cmb/toast/pull/302 -.. _`#301`: https://github.com/hpc4cmb/toast/pull/301 -.. _`#300`: https://github.com/hpc4cmb/toast/pull/300 -.. _`#299`: https://github.com/hpc4cmb/toast/pull/299 - - -2.3.1 (2019-10-14) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Fix bug when writing FITS maps serially. -* Improve printing of Environment and TOD classes (PR `#294`_). -* Fix a race condition (PR `#292`_). -* Control the Numba backend from TOAST (PR `#283`_, `#291`_). -* Functional TOAST map-maker (PR `#288`_). -* Large improvements to ground sim example (PR `#290`_). -* Overhaul examples to match 2.3.0 changes (PR `#286`_). -* Handle small angles and improve unit tests for healpix. - -.. _`#294`: https://github.com/hpc4cmb/toast/pull/294 -.. _`#292`: https://github.com/hpc4cmb/toast/pull/292 -.. _`#283`: https://github.com/hpc4cmb/toast/pull/283 -.. _`#291`: https://github.com/hpc4cmb/toast/pull/291 -.. _`#288`: https://github.com/hpc4cmb/toast/pull/288 -.. _`#290`: https://github.com/hpc4cmb/toast/pull/290 -.. _`#286`: https://github.com/hpc4cmb/toast/pull/286 - - -2.3.0 (2019-08-13) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Rewrite of internal compiled codebase and build system. -* Move common pipeline configuration to a new module (PR `#280`_). -* Add scan synchronous simulation operator (PR `#278`_). - -.. _`#280`: https://github.com/hpc4cmb/toast/pull/280 -.. _`#278`: https://github.com/hpc4cmb/toast/pull/278 diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 6c8ca912d..000000000 --- a/docs/conf.py +++ /dev/null @@ -1,298 +0,0 @@ -# -*- coding: utf-8 -*- -# -import sys -import os - -# This is a hybrid package with a compiled extension. The extension must be -# built before running sphinx. -try: - import toast -except ImportError: - print( - "Before running sphinx, you must have built and installed" - " toast and have it in your search path" - ) - raise - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - "sphinx.ext.autodoc", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", - "sphinx.ext.mathjax", - "sphinx.ext.viewcode", - "sphinx.ext.napoleon", -] - -# Napoleon settings -# napoleon_google_docstring = True -# napoleon_numpy_docstring = True -# napoleon_include_init_with_doc = False -# napoleon_include_private_with_doc = False -# napoleon_include_special_with_doc = True -# napoleon_use_admonition_for_examples = False -# napoleon_use_admonition_for_notes = False -# napoleon_use_admonition_for_references = False -# napoleon_use_ivar = False -# napoleon_use_param = True -# napoleon_use_rtype = True - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = u"TOAST" -copyright = u"2015-2020, Theodore Kisner, Reijo Keskitalo, Andrea Zonca" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The full version, including alpha/beta/rc tags. -release = toast.__version__ -# Use the full version -version = release - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ["_build", "**.ipynb_checkpoints"] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# nbsphinx options -nbsphinx_execute = "never" - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -keep_warnings = True - -# Include TO-DO items -todo_include_todos = True - -# Include functions that begin with an underscore, e.g. _private(). -napoleon_include_private_with_doc = True - -# -- Options for autodoc -------------------------------------------------- - -# autoclass_content = 'both' - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -on_rtd = os.environ.get("READTHEDOCS") == "True" -if on_rtd: - html_theme = "sphinx_rtd_theme" -else: - html_theme = "sphinx_rtd_theme" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -html_theme_options = {"collapse_navigation": False} - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = "TOASTdocs" - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - #'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ( - "index", - "TOAST.tex", - u"TOAST Documentation", - u"Theodore Kisner, Reijo Keskitalo, Andrea Zonca", - "manual", - ) -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ("index", "toast", u"TOAST Documentation", [u"Theodore Kisner, Reijo Keskitalo"], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - "index", - "TOAST", - u"TOAST Documentation", - u"Theodore Kisner, Reijo Keskitalo", - "TOAST", - "One line description of project.", - "Miscellaneous", - ) -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False diff --git a/docs/data.rst b/docs/data.rst deleted file mode 100644 index 7d6a97dbe..000000000 --- a/docs/data.rst +++ /dev/null @@ -1,157 +0,0 @@ -.. _data: - -Data -================= - -TOAST works with data organized into *observations*. Each observation is independent of -any other observation. An observation consists of co-sampled detectors for some span of -time. The intrinsic detector noise is assumed to be stationary within an observation. -Typically there are other quantities which are constant for an observation (e.g. -elevation, weather conditions, satellite procession axis, etc). - -A TOAST workflow consists of one or more (distributed) observations representing the data, and a series of *operators* that "do stuff" with this data. The following sections detail the classes that represent TOAST data sets and how that data is distributed among many MPI processes. - -Related Classes ------------------- - -An observation is just a dictionary with at least one member ("tod") which is an -instance of a class that derives from the `toast.TOD` base class. Every experiment will -have their own TOD derived classes, but TOAST includes some built-in ones as well. - -TOD Base Class -~~~~~~~~~~~~~~~~~~~ - -The base class is not used directly, but provides the interfaces required by all derived classes. The inputs to the TOD base class constructor are at least: - -1. The detector names for the observation. -2. The number of samples in the observation. -3. The geometric offset of the detectors from the boresight. -4. Information about how detectors and samples should distributed among processes. - -.. autoclass:: toast.tod.TOD - :members: - -The TOD class can act as a storage container for different "flavors" of timestreams as -well as a source and sink for the observation data (with the `read_*()` and `write_*()` -methods). The TOD base class has one member which is a `Cache` class. This `cache` -member is where alternate flavors of the timestream data are stored. - -Cache Class -~~~~~~~~~~~~~~~~~~~~~ - -A `Cache` class behaves like a dictionary of N-dimensional numpy arrays. A restricted set of basic dtypes are supported. The memory for each buffer is allocated outside -of Python in flat-packed and aligned storage. This means that it can be explicitly managed / freed, and can also be used directly in routines that require aligned memory for SIMD operations. - -.. autoclass:: toast.cache.Cache - :members: - -Noise Model -~~~~~~~~~~~~~~~~ - -Each observation can also have a noise model associated with it. An instance of a Noise -class (or derived class) describes the noise properties for all detectors in the -observation. - -.. autoclass:: toast.tod.Noise - :members: - -Intervals -~~~~~~~~~~~~~~~~~ - -Within each TOD object, a process contains some local set of detectors and range of -samples. That range of samples may contain one or more contiguous "chunks" that were -used when distributing the data. Separate from this data distribution, TOAST has the -concept of valid data "intervals". This list of intervals applies to the whole -observation, and all processes have a copy of this list. This list of intervals is -useful to define larger sections of data than what can be specified with per-sample -flags. A single interval looks like this: - -.. autoclass:: toast.tod.Interval - :members: - - -The Data Class -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The data used by a TOAST workflow consists of a list of observations, and is -encapsulated by the `toast.Data` class. - -.. autoclass:: toast.dist.Data - :members: - -If you are running with a single process, that process has all observations and all data -within each observation locally available. If you are running with more than one -process, the data with be distributed across processes. - - -Distribution --------------------------- - -Although you can use TOAST without MPI, the package is designed for data that is -distributed across many processes. When passing the data through a toast workflow, the -data is divided up among processes based on the details of the `toast.Comm` class that -is used and also the shape of the process grid in each observation. - -A toast.Comm instance takes the global number of processes available (MPI.COMM_WORLD) -and divides them into groups. Each process group is assigned one or more observations. -Since observations are independent, this means that different groups can be -independently working on separate observations in parallel. It also means that -inter-process communication needed when working on a single observation can occur with a -smaller set of processes. - -.. autoclass:: toast.mpi.Comm - :members: - -Just to reiterate, if your `toast.Comm` has multiple process groups, then each group -will have an independent list of observations in `toast.Data.obs`. - -What about the data *within* an observation? A single observation is owned by exactly -one of the process groups. The MPI communicator passed to the TOD constructor is the -group communicator. Every process in the group will store some piece of the observation -data. The division of data within an observation is controlled by the `detranks` option -to the TOD constructor. This option defines the dimension of the rectangular "process -grid" along the detector (as opposed to time) direction. Common values of `detranks` -are: - - * "1" (processes in the group have all detectors for some slice of time) - * Size of the group communicator (processes in the group have some of the detectors for the whole time range of the observation) - -The detranks parameter must divide evenly into the number of processes in the group communicator. - -Examples -~~~~~~~~~~~~~~~ - -It is useful to walk through the process of how data is distributed for a simple case. We have some number of observations in our data, and we also have some number of MPI processes in our world communicator: - -.. figure:: _static/data_dist_1.png - -Starting point: Observations and MPI Processes. - -.. figure:: _static/data_dist_2.png - -Defining the process groups: We divide the total processes into equal-sized groups. - -.. figure:: _static/data_dist_3.png - -Assign observations to groups: Each observation is assigned to exactly one group. Each group has one or more observations. - -.. figure:: _static/data_dist_4.png - -The `detranks` TOD constructor argument specifies how data **within** an observation is distributed among the processes in the group. The value sets the dimension of the process grid in the detector direction. In the above case, `detranks = 1`, so the process group is arranged in a one-dimensional grid in the time direction. - -.. figure:: _static/data_dist_5.png - -In the above case, the `detranks` parameter is set to the size of the group. This means that the process group is arranged in a one-dimensional grid in the process direction. - -Now imagine a more complicated case (not currently used often if at all) where the -process group is arranged in a two-dimensional grid. This is useful as a visualization -exercise. Let's say that MPI.COMM_WORLD has 24 processes. We split this into 4 groups -of 6 procesess. There are 6 observations of varying lengths and every group has one or 2 -observations. For this case, we are going to use `detranks = 2`. Here is a picture of -what data each process would have. The global process number is shown as well as the -rank within the group: - -.. image:: _static/toast_data_dist.png - - -.. include:: data_builtin.inc diff --git a/docs/data_builtin.inc b/docs/data_builtin.inc deleted file mode 100644 index dea3a1713..000000000 --- a/docs/data_builtin.inc +++ /dev/null @@ -1,40 +0,0 @@ -.. _databuiltin: - -Built-in Data Support ------------------------------ - -In most cases of "real" experiments / telescopes, there will be custom TOAST classes to represent the data. However, TOAST comes with support for some (mainly simulated) data types. These are useful when simulating proposed experiments that do not yet have detailed specifications. Once a project reaches the level of having detailed hardware specifications (either designed or measured), then it should implement custom classes for that instrument description and data I/O or simulation. - -Simulated TOD Classes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Recall that a ``TOD`` class represents the properties of some detectors from a telescope for one observation. This includes its physical location / motion through space as well as geometric locations of the detectors and (in the case of real data) methods to read detector data. For simulated TOD classes, we simulate the telescope boresight pointing and detector properties. We do **not** simulate detector data as part of the TOD class- that is done by various simulation operators that accumulate signal and noise from various sources. For generic satellite simulations, we have: - -.. autofunction:: toast.todmap.slew_precession_axis - -.. autofunction:: toast.todmap.satellite_scanning - -.. autoclass:: toast.todmap.TODSatellite - :members: - -For generic ground-based simulations we have: - -.. autoclass:: toast.todmap.TODGround - :members: - - -Simulated Noise Properties -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One common noise model that is frequency used in simulations is a 1/f spectrum with white noise. - -.. autoclass:: toast.tod.AnalyticNoise - :members: - - -Simulated Intervals -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Simulating regular data intervals is common task for many simulations: - -.. autofunction:: toast.tod.regular_intervals diff --git a/docs/dev.rst b/docs/dev.rst deleted file mode 100644 index f6b1ca660..000000000 --- a/docs/dev.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. _dev: - -Developer Guidelines -======================= - -Everyone contributing code to TOAST should aim to follow these guidelines in order to -keep the code consistent. Whenever you make changes and before opening a pull request, -run the script ``src/format_source.sh`` to apply the standard formatting rules to the -Python and C++ code. If you use an editor with some other automatic code formatting, -you should disable it unless you can configure it identically to the action of this -script. - - -Python Code -------------------- - -We aim to follow PEP8 style guidelines whenever possible. There are some reasonable -exceptions to this. In particular, import statements might not always be placed at the -top of the code if: - -- The import is an optional feature that has large performance impacts and which is only used infrequently. For example matplotlib, astropy, etc. - -- Some initialization code is needed prior to the import statement. For example, setting the matplotlib backend. - -Other style choices: - -- Double quotes for strings unless the string contains double quotes, resulting in excessive backslash escaping. This should be handled automatically by the code formatter. - -We use the "black" command line tool to format our source. This needs to be installed -on your system before running the ``format_source.sh`` script. - - -Compiled Code -------------------- - -For consistency with python, class names follow python CamelCase convention. Function -names follow python_underscore_convention. Formatting is set by uncrustify with a -custom config file and this is run by the ``format_source.sh`` script. - -All code that is exposed through pybind11 is in a single toast namespace. Nested -namespaces may be used for code that is internal to the C++ code. - -The "using" statement is allowed for aliasing a specific class or type:: - - using ShapeContainer = py::detail::any_container; - -But should **not** be used to import an entire namespace:: - - using std; - -Header files included with "#include" should use angle brackets ("<>") for the header -file name. If this fails for some reason then that indicates a problem with the build -system and its header file search paths. Using double quotes for "#include" statements -is OK when including raw source files in the same directory (for example, when including -raw \*.cpp contents generated by external scripts). - -When including C standard header files in C++, use the form:: - - #include - -Rather than:: - - #include - -Pointer / reference declarations: this allows reading from right to left as "a pointer -to a constant double" or "a reference to a constant double":: - - double const * data - double const & data - -Not:: - - const double * data - const double & data - -When indexing the size of an STL container, the index variable should be either of the -size type declared in the container class or size_t. - -When describing time domain sample indices or intervals, we using int64_t everywhere for -consistency. This allows passing, e.g. "-1" to communicate unspecified intervals or -sample indices. - -Single line conditional statements:: - - if (x > 0) y = x; - -Are permitted if they fit onto a single line. Otherwise, insert braces. - -Internal toast source files should not include the main "toast.hpp". Instead -they should include the specific headers they need. For example:: - - #include - #include - #include - -If attempting to vectorize code with OpenMP simd constructs, be sure to check that any -data array used in the simd region are aligned (see toast::is_aligned). Otherwise this -can result in silent data corruption. - -Documentation: sphinx is used. All python code should have docstrings. All C++ code -exposed through pybind11 should also have docstrings defined in the bindings. C++ code -that is not exposed to python is considered internal, expert-level code that does not -require formal documentation. However, such code should have sufficient comments to -describe the algorithm and design choices. - -Testing Workflow --------------------------- - -We are using a github workflow to pull docker containers with our dependencies and run -our unit tests. Those docker containers are re-generated whenever a new tag is made on -the `cmbenv git repository `_. So if there are -dependencies that need to be updated, open a PR against cmbenv which updates the version -or build in the package file. After merging and tagging a new cmbenv release the -updated docker images will be available in an hour or two and be used automatically. - -Release Process ---------------------------- - -There are some github workflows that only run when a new tag is created. Unless you are -sure everything works, create a "release candidate" tag first. Before making a tag, -ensure that the `docs/changes.rst` file contains all pull requests that have been merged -since the last tag. Also edit the `src/toast/RELEASE` file and set the version to a -`PEP-440 compatible string `_. Next go onto -the github releases page and create a new release from the master branch. Briefly, the -format for a stable release, a release candidate or alpha version is: - - 2.6.9 - 2.6.7rc2 - 2.6.8a1 - -After tagging the release, verify that the github workflow to deploy pip wheels runs and -uploads these to PyPI. The conda-forge bots will automatically detect the new tag and -open a PR to update the feedstock. Also, after the release is complete, update the -`RELEASE` file to be at the "alpha" of the next release. For example, after tagging -version 3.4.5, set the version in the RELEASE file to 3.4.6a1. This version is **only** -used when building pip wheels. Anyone installing locally with setup.py or with pip -running on the local source tree will get a version constructed from the number of -commits since the last git tag. diff --git a/docs/doc_requirements.txt b/docs/doc_requirements.txt new file mode 100644 index 000000000..0d5fb1e04 --- /dev/null +++ b/docs/doc_requirements.txt @@ -0,0 +1,8 @@ +mkdocs +mkdocstrings +mkdocstrings-python +mkdocs-material +mkdocs-jupyter>=0.24.7 +nbconvert +wurlitzer +sympy diff --git a/docs/docs/design/data_model.md b/docs/docs/design/data_model.md new file mode 100644 index 000000000..7dea47ef4 --- /dev/null +++ b/docs/docs/design/data_model.md @@ -0,0 +1,16 @@ +# Data Model + +- Domain decomposition + + + +## Data Quality Flags + +Detector data can be "flagged" or cut for a variety of reasons. Sometimes a flag +indicates that the data is corrupted in some way and should not be used. In +other cases, flags are used to classify data with particular properties. For +example, samples crossing a planet or while the telescope is in a turnaround. +TOAST supports flags that can be applied for an entire detector within an +observation, and also flags for individual detector samples. + +## Pointing Model diff --git a/docs/docs/design/overview.md b/docs/docs/design/overview.md new file mode 100644 index 000000000..9a6c88db3 --- /dev/null +++ b/docs/docs/design/overview.md @@ -0,0 +1,32 @@ +# Overview + + +The TOAST framework contains: + +- Tools for distributing data among many processes and performing collective operations using MPI. +- Tools for performing operations on the local pieces of the data +- Generic operators for common processing tasks (filtering, pointing expansion, map-making) +- Basic classes for performing I/O in a limited set of formats +- Well-defined interfaces for adding custom I/O classes and processing operators + +The highest-level control of the workflow is done by the user, often by writing +a small Python script or notebook (some examples are included). Such scripts +make use of TOAST functionality for distributing data and then call built-in or +custom operators to simulate and / or process the timestream data. + +## Data Distribution + +- Domain decomposition + + + +## Data Quality Flags + +Detector data can be "flagged" or cut for a variety of reasons. Sometimes a flag +indicates that the data is corrupted in some way and should not be used. In +other cases, flags are used to classify data with particular properties. For +example, samples crossing a planet or while the telescope is in a turnaround. +TOAST supports flags that can be applied for an entire detector within an +observation, and also flags for individual detector samples. + +## Pointing Model diff --git a/docs/docs/design/parallelism.md b/docs/docs/design/parallelism.md new file mode 100644 index 000000000..f2fcebdb6 --- /dev/null +++ b/docs/docs/design/parallelism.md @@ -0,0 +1,6 @@ +# Parallelism + + +## MPI + +## Threading and Accelerators diff --git a/docs/docs/design/pointing_weights.ipynb b/docs/docs/design/pointing_weights.ipynb new file mode 100644 index 000000000..bd067885f --- /dev/null +++ b/docs/docs/design/pointing_weights.ipynb @@ -0,0 +1,878 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Pointing Matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "%config InlineBackend.figure_format = \"retina\"\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import seaborn as sns\n", + "sns.set()\n", + "plt.rcParams['figure.figsize'] = (10.0, 6.0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "import sympy as sym\n", + "from sympy.vector import CoordSys3D\n", + "\n", + "sym.init_printing()" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## Background\n", + "\n", + "The \"Pointing Matrix\" in TOAST is represented by two types of operations. The first is the mapping from geometric detector quaternion pointing to a pixelized representation of the sky. The second is the model of the detector response to incoming polarized light. This model can be expressed as the application of Mueller matrices representing optical elements in the system. The incoming light can be expressed as a vector of Stokes parameters I, Q, U, and V.\n", + "\n", + "The Stokes parameters are defined with respect to the local meridian at the detector line of sight. In the TOAST formalism, the detector frame has the Z axis pointing along the detector line of sight and the X axis aligned with the direction of maximum polarization response. For this exercise, we will use the COSMO convention for the Stokes parameters, since it conveniently also has the Z axis along the line of sight. The final result is easy to swap between COSMO / IAU simply by changing the sign of the U Stokes parameter. In some scenarios, it can be convenient to look at the various angles from the perspective of the instrument \"looking out\" at the sky (with the detector Z axis going \"into the page\"). In other cases it makes more sense to visualize the situation \"looking in\" from the sky. The figures below clearly label which case is being displayed.\n", + "\n", + "![COSMO_Conventions](pointing_weights_figs/COSMO_Pol_Conventions_v3.png)" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "### Definitions\n", + "\n", + "We will use $alpha$ to represent the angle of right-handed rotation from the meridian to the detector polarization orientation (the detector frame X axis) about the line of sight (detector Z axis). We use $omega$ to represent the right-handed angle of rotation, about the line of sight, from the meridian to a direction parallel to the HWP fast axis. The cross-polar leakage of the linearly polarized detector is $epsilon$. To visually simplify things, we define the polarization coefficient: \n", + "\n", + "$$\n", + "C = \\frac{1 - \\epsilon}{1 + \\epsilon}\n", + "$$\n", + "\n", + "And note that there is a factor of $1/2$ that can be included in an overall calibration factor in the resulting measured output power." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], + "source": [ + "alpha = sym.Symbol(r\"\\alpha\")\n", + "omega = sym.Symbol(r\"\\omega\")\n", + "epsilon = sym.Symbol(r\"\\epsilon\")\n", + "C = sym.Symbol(\"C\")\n", + "alpha, omega, epsilon, C" + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "## Mueller Matrix Representation\n", + "\n", + "Assume we have an input Stokes vector:\n", + "\n", + "$$\n", + "\\vec{S}_{in} = \\left[\n", + "\\begin{array}{c}\n", + "I_{in}\\\\\n", + "Q_{in}\\\\ \n", + "U_{in}\\\\ \n", + "V_{in}\n", + "\\end{array}\n", + "\\right]\n", + "$$\n", + "\n", + "In the case of no HWP and just a partial linear polarizer followed by a total power measurement, the resulting measured power is:\n", + "\n", + "$$\n", + "P_{out} = \\mathbf{T}_{power} \\cdot \\mathbf{M}_{det} \\;\\vec{S}_{in}\n", + "$$\n", + "\n", + "Where the total power measurement $\\mathbf{T}$ is simply the sum of the top row of the final Mueller matrix. If we introduce a rotating HWP followed by the fixed linear polarizer and then a total power measurement we get:\n", + "\n", + "$$\n", + "P_{out} = \\mathbf{T}_{power} \\cdot \\mathbf{M}_{det} \\cdot \\mathbf{M}_{HWP}(t) \\;\\vec{S}_{in}\n", + "$$\n", + "\n", + "The detector and HWP Mueller matrices include a rotational coordinate transform:\n", + "\n", + "$$\n", + "\\mathbf{M}_{HWP} = \\mathbf{R}_{HWP}^{-1}\\; \\mathbf{M}_{Fixed\\ HWP}\\; \\mathbf{R}_{HWP}\n", + "$$\n", + "\n", + "Where the rotation matrix transforms from the measurement frame to the local coordinates of the HWP. Similarly the detector Mueller matrix is an (imperfect) linear polarizer with some rotation from the measurement frame:\n", + "\n", + "$$\n", + "\\mathbf{M}_{det} = \\mathbf{R}_{det}^{-1}\\; \\mathbf{M}_{Linear\\ Pol}\\; \\mathbf{R}_{det}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### HWP Matrix\n", + "\n", + "The ideal, local HWP has Mueller matrix of:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "# Ideal HWP in local frame:\n", + "Lhwp = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, 1, 0, 0],\n", + " [0, 0, -1, 0],\n", + " [0, 0, 0, -1],\n", + "])\n", + "Lhwp" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "and the rotation matrix from the coordinate frame to the local frame is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "Rhwp = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(2 * omega), -sym.sin(2 * omega), 0],\n", + " [0, sym.sin(2 * omega), sym.cos(2 * omega), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rhwp" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "For simplifying the algebra below, we use $b = 2\\omega$. The inverse coordinate transform is a result of swapping $\\omega$ for $-\\omega$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "b = sym.Symbol(r\"b\")\n", + "\n", + "Rhwp = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(b), -sym.sin(b), 0],\n", + " [0, sym.sin(b), sym.cos(b), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rhwp" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "Rhwpinv = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(b), sym.sin(b), 0],\n", + " [0, -sym.sin(b), sym.cos(b), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rhwpinv" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "And then the final HWP Mueller matrix becomes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "Mhwp = sym.simplify(Rhwpinv * Lhwp * Rhwp)\n", + "Mhwp" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "### Linearly Polarized Detector\n", + "\n", + "A (partial) linear polarizer has the local Mueller matrix:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "Ldet = sym.Matrix([\n", + " [1, C, 0, 0],\n", + " [C, 1, 0, 0],\n", + " [0, 0, 0, 0],\n", + " [0, 0, 0, 0],\n", + "])\n", + "Ldet" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "The Mueller matrix which rotates a Stokes vector in a right-handed counter-clockwise sense from the coordinate frame to the local frame is again given by:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "Rdet = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(2 * alpha), -sym.sin(2 * alpha), 0],\n", + " [0, sym.sin(2 * alpha), sym.cos(2 * alpha), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rdet" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "For simplifying the algebra below, we use $a = 2\\alpha$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "a = sym.Symbol(r\"a\")\n", + "Rdet = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(a), -sym.sin(a), 0],\n", + " [0, sym.sin(a), sym.cos(a), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rdet" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "The inverse transform can be obtained by evaluating this at $-\\alpha$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "Rdetinv = sym.Matrix([\n", + " [1, 0, 0, 0],\n", + " [0, sym.cos(a), sym.sin(a), 0],\n", + " [0, -sym.sin(a), sym.cos(a), 0],\n", + " [0, 0, 0, 1],\n", + "])\n", + "Rdetinv" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "The final detector Mueller matrix in the measurement frame is then:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "Mdet = sym.simplify(Rdetinv * Ldet * Rdet)\n", + "Mdet" + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "### Final Expression - Without HWP\n", + "\n", + "The optical response without a HWP is just the linear polarized detector result above. The output Stokes weights are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": {}, + "outputs": [], + "source": [ + "s_I = Mdet[0, 0]\n", + "s_I" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28", + "metadata": {}, + "outputs": [], + "source": [ + "s_Q = Mdet[0, 1]\n", + "s_Q" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "s_U = Mdet[0, 2]\n", + "s_U" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "So the final measured power is:\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ Q_{in} \\cos \\left( 2 \\alpha \\right)\n", + "+ U_{in} \\sin \\left( 2 \\alpha \\right) \\right]\n", + "\\right]\\qquad (COSMO)\n", + "$$\n", + "\n", + "OR\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ Q_{in} \\cos \\left( 2 \\alpha \\right)\n", + "- U_{in} \\sin \\left( 2 \\alpha \\right) \\right]\n", + "\\right]\\qquad (IAU)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "Consider the trivial case where the focalplane coordinates are aligned with the coordinate axes, so that $\\alpha$ is exactly the orientation of the detector in the coordinate frame. For several different $\\alpha$ values (in COSMO convention) we have:" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 0) = & \\;1 \\\\\n", + "U_{weight}(\\alpha = 0) = & \\;0\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 45) = & \\;0 \\\\\n", + "U_{weight}(\\alpha = 45) = & \\;1\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 90) = & \\;-1 \\\\\n", + "U_{weight}(\\alpha = 90) = & \\;0\n", + "\\end{aligned}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "33", + "metadata": {}, + "source": [ + "### Final Expression - Including HWP\n", + "\n", + "The combined optical response of the HWP and detector matrices are then:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "Mopt = sym.simplify(Mdet * Mhwp)\n", + "Mopt" + ] + }, + { + "cell_type": "markdown", + "id": "35", + "metadata": {}, + "source": [ + "And the output Stokes weights are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36", + "metadata": {}, + "outputs": [], + "source": [ + "s_I = Mopt[0, 0]\n", + "s_I" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "s_Q = Mopt[0, 1]\n", + "s_Q" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "s_U = Mopt[0, 2]\n", + "s_U" + ] + }, + { + "cell_type": "markdown", + "id": "39", + "metadata": {}, + "source": [ + "So the final measured power is:\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ Q_{in} \\cos \\left( 2(\\alpha - 2\\omega) \\right)\n", + "- U_{in} \\sin \\left( 2(\\alpha - 2\\omega) \\right) \\right]\n", + "\\right]\\qquad (COSMO)\n", + "$$\n", + "\n", + "OR\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ Q_{in} \\cos \\left( 2(\\alpha - 2\\omega) \\right)\n", + "+ U_{in} \\sin \\left( 2(\\alpha - 2\\omega) \\right) \\right]\n", + "\\right]\\qquad (IAU)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "Consider the trivial case where the focalplane coordinates are aligned with the coordinate axes, so that $\\alpha$ and $\\omega$ are directly the orientations of the detector and HWP in the coordinate frame. In that case, consider a fixed HWP aligned with the meridian ($\\omega$ = 0) for several different $\\alpha$ values (in COSMO convention):" + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 0) = & \\;1 \\\\\n", + "U_{weight}(\\alpha = 0) = & \\;0\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 45) = & \\;0 \\\\\n", + "U_{weight}(\\alpha = 45) = & \\;-1\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(\\alpha = 90) = & \\;-1 \\\\\n", + "U_{weight}(\\alpha = 90) = & \\;0\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "Note the sign flip of the U component at 45 degrees, compared to the case without a HWP present in the optical path." + ] + }, + { + "cell_type": "markdown", + "id": "42", + "metadata": {}, + "source": [ + "## Detector Response in TOAST\n", + "\n", + "Our starting point is a detector quaternion at each sample that rotates the coordinate frame on the sky to the detector frame, with the Z axis along the line of sight and the X axis along the polarization sensitive direction. In the detector frame, the vector along the meridian is offset by an angle of $-\\alpha$. Recall that our detector coordinate frame is offset from the overall focalplane frame. The detector frame is also rotated by an angle ${\\gamma}_{D}$. The HWP angle (${\\gamma}_{H}(t)$) in the detector frame is time varying and measured from the same reference point:\n", + "\n", + "![Detector Frame](pointing_weights_figs/det_frame.png)\n", + "\n", + "For the case with no HWP, we just need the angle $\\alpha$. If we do have a HWP, then we can use the figure above to express $\\omega$ in terms of our known quantities. From this we can see that $\\omega = \\alpha + {\\gamma}_{H}(t) - {\\gamma}_{D}$. Substituting this we get (using COSMO convention, which is the default):\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ Q_{in} \\cos \\left( 2 \\left( \\alpha - 2 \\left[ \\alpha + {\\gamma}_{H}(t) - {\\gamma}_{D} \\right] \\right) \\right)\n", + "- U_{in} \\sin \\left( 2 \\left( \\alpha - 2 \\left[ \\alpha + {\\gamma}_{H}(t) - {\\gamma}_{D} \\right] \\right) \\right)\n", + "\\right] \\right]\n", + "$$\n", + "\n", + "Expanding:\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ \n", + "Q_{in} \\cos \\left( 2 \\left( \\alpha - 2 \\alpha - 2 {\\gamma}_{H}(t) + 2 {\\gamma}_{D} \\right) \\right)\n", + "- U_{in} \\sin \\left( 2 \\left( \\alpha - 2 \\alpha - 2 {\\gamma}_{H}(t) + 2 {\\gamma}_{D} \\right) \\right)\n", + "\\right]\n", + "\\right]\n", + "$$\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ \n", + "Q_{in} \\cos \\left( 2 \\left( - \\alpha - 2 {\\gamma}_{H}(t) + 2 {\\gamma}_{D} \\right) \\right)\n", + "- U_{in} \\sin \\left( 2 \\left( - \\alpha - 2 {\\gamma}_{H}(t) + 2 {\\gamma}_{D} \\right) \\right)\n", + "\\right] \n", + "\\right]\n", + "$$\n", + "\n", + "$$\n", + "P_{out} = \\frac{1}{2} \\left[\n", + "I_{in} + \\frac{1 - \\epsilon}{1 + \\epsilon} \\left[ \n", + "Q_{in} \\cos \\left( 2 \\left[ 2 \\left( {\\gamma}_{D} - {\\gamma}_{H}(t) \\right) - \\alpha \\right] \\right) \n", + "- U_{in} \\sin \\left( 2 \\left[ 2 \\left( {\\gamma}_{D} - {\\gamma}_{H}(t) \\right) - \\alpha \\right] \\right)\n", + "\\right]\n", + "\\right]\n", + "$$\n", + "\n", + "This gives us our total power measurement in terms of a fixed, per-detector offset, the HWP angle in the focalplane frame, and the orientation of the detector frame (the $\\alpha$ angle) at each sample." + ] + }, + { + "cell_type": "markdown", + "id": "43", + "metadata": {}, + "source": [ + "### Example\n", + "\n", + "As a sanity check, consider a scenario where the focalplane X axis is aligned with the coordinate system \"South\" direction in the figure above. Also choose ${\\gamma}_{D}$ to be 45 degrees. In this case, $\\alpha == {\\gamma}_{D}$ and $2\\alpha = 90^{\\circ}$.\n", + "\n", + "In the case of no HWP and using COSMO convention, we have:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(45) = & \\;\\cos \\left( 2 \\alpha \\right) \\\\\n", + "Q_{weight}(45) = & \\;0\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "U_{weight}(45) = & \\;\\sin \\left( 2 \\alpha \\right) \\\\\n", + "U_{weight}(45) = & \\;1\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "The Stokes Q weight is zero and the Stokes U weight is +1, which makes sense since the detector is aligned with the positive U axis. In the case of a rotating HWP, our Q weight is:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight} = & \\;\\cos \\left( 2 \\left[ 2 \\left( {\\gamma}_{D} - {\\gamma}_{H}(t) \\right) - \\alpha \\right] \\right) \\\\\n", + "& \\;\\text{(substitute ${\\gamma}_{D}=\\alpha$)} \\\\\n", + "Q_{weight} = & \\;\\cos \\left( 2 \\left[ 2 \\alpha - 2 {\\gamma}_{H}(t) - \\alpha \\right] \\right) \\\\\n", + "Q_{weight} = & \\;\\cos \\left( 2 \\alpha - 4 {\\gamma}_{H}(t) \\right)\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "and the U weight is:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "U_{weight} = & \\; - \\sin \\left( 2 \\left[ 2 \\left( {\\gamma}_{D} - {\\gamma}_{H}(t) \\right) - \\alpha \\right] \\right) \\\\\n", + "& \\;\\text{(substitute ${\\gamma}_{D}=\\alpha$)} \\\\\n", + "U_{weight} = & \\; - \\sin \\left( 2 \\left[ 2 \\alpha - 2 {\\gamma}_{H}(t) - \\alpha \\right] \\right) \\\\\n", + "U_{weight} = & \\; - \\sin \\left( 2 \\alpha - 4 {\\gamma}_{H}(t) \\right)\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "Consider what happens when the fast axis of the HWP is aligned with the detector orientation (${\\gamma}_{H} = \\alpha = {\\gamma}_{D} = 45^{\\circ}$). In that scenario we have:\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "Q_{weight}(45,HWP) = & \\;\\cos \\left( - 2 \\alpha \\right)\\\\\n", + "Q_{weight}(45,HWP) = & \\;0\n", + "\\end{aligned}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{aligned}\n", + "U_{weight}(45,HWP) = & \\; - \\sin \\left( - 2 \\alpha \\right)\\\\\n", + "U_{weight}(45,HWP) = & \\;1\n", + "\\end{aligned}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "### Implementation\n", + "\n", + "Given the previous equations, for both the HWP and non-HWP cases we need to use our detector pointing to determine the $\\alpha$ angle at each sample. We can use our detector quaternions to rotate the sky coordinate axes to the detector frame. The resulting direction (detector Z axis) and orientation (detector X axis / polarization sensitive direction) vectors are:\n", + "\n", + "$$\n", + "\\vec{V}_{direction} = \\vec{V}_{d} = Q_{det} (\\hat{Z}) = V_{dx}\\,\\hat{i} + V_{dy}\\,\\hat{j} + V_{dz}\\,\\hat{k}\n", + "$$\n", + "$$\n", + "\\vec{V}_{orientation} = \\vec{V}_{o} = Q_{det} (\\hat{X}) = V_{ox}\\,\\hat{i} + V_{oy}\\,\\hat{j} + V_{oz}\\,\\hat{k}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "N = CoordSys3D(\"N\")\n", + "Vdx = sym.Symbol(\"Vdx\")\n", + "Vdy = sym.Symbol(\"Vdy\")\n", + "Vdz = sym.Symbol(\"Vdz\")\n", + "Vox = sym.Symbol(\"Vox\")\n", + "Voy = sym.Symbol(\"Voy\")\n", + "Voz = sym.Symbol(\"Voz\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46", + "metadata": {}, + "outputs": [], + "source": [ + "Vd = Vdx * N.i + Vdy * N.j + Vdz * N.k\n", + "Vd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": {}, + "outputs": [], + "source": [ + "Vo = Vox * N.i + Voy * N.j + Voz * N.k\n", + "Vo" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "Given these, we can construct the vector orthogonal to the detector line of sight ($\\vec{V}_{d}$) which is aligned with the local meridian:\n", + "\n", + "$$\n", + "\\vec{V}_{meridian} = \\vec{V}_{m} = V_{dz}\\cos \\left( {\\tan}^{-1} \\left( \\frac{V_{dy}}{V_{dx}} \\right) \\right)\\;\\hat{i} + V_{dz}\\sin \\left( {\\tan}^{-1} \\left( \\frac{V_{dy}}{V_{dx}} \\right) \\right)\\;\\hat{j} - \\sqrt{1 - V_{dz}^2}\\;\\hat{k}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49", + "metadata": {}, + "outputs": [], + "source": [ + "Vmx = sym.Symbol(\"Vmx\")\n", + "Vmy = sym.Symbol(\"Vmy\")\n", + "Vmz = sym.Symbol(\"Vmz\")\n", + "Vm = Vmx * N.i + Vmy * N.j + Vmz * N.k\n", + "Vm" + ] + }, + { + "cell_type": "markdown", + "id": "50", + "metadata": {}, + "source": [ + "This vector is co-planar with the detector X / Y coordinate axes. The rotation angle from the meridian vector to the detector X axis ($\\vec{V}_{o}$) is the $\\alpha$ angle above, and is given by (using the fact that $\\vec{V}_{d}$ is the normal to the plane):\n", + "\n", + "$$\n", + "\\alpha = {\\tan}^{-1} \\left( \\frac{ \\left( \\vec{V}_{m} \\times \\vec{V}_{o} \\right) \\cdot \\vec{V}_{d}}{\\vec{V}_{m} \\cdot \\vec{V}_{0}} \\right)\n", + "$$\n", + "\n", + "Which in terms of components is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51", + "metadata": {}, + "outputs": [], + "source": [ + "sym.atan2((Vm.cross(Vo)).dot(Vd), Vm.dot(Vo))" + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "Pulling out the minus sign and formatting nicely we get:\n", + "\n", + "$$\n", + "\\alpha = {\\tan}^{-1} \\left(\n", + " \\frac{\n", + " V_{dx} (V_{my} V_{oz} - V_{mz} V_{oy}) - V_{dy} (V_{mx} V_{oz} - V_{mz} V_{ox}) + V_{dz} (V_{mx} V_{oy} - V_{my} V_{ox})\n", + " }{\n", + " V_{mx} V_{ox} + V_{my} V_{oy} + V_{mz} V_{oz}\n", + " }\n", + "\\right)\n", + "$$\n", + "\n", + "So computing the Stokes weights at each sample involves appling the detector quaternion to two vectors, a few trig functions to get the components of $\\vec{V}_{m}$, and then the calculation of the $\\alpha$ angle." + ] + }, + { + "cell_type": "markdown", + "id": "53", + "metadata": {}, + "source": [ + "### Stokes Weights Unit Tests\n", + "\n", + "The following plots are generated by the unit tests for different cases of input Stokes parameters and HWP state. For each case in the following plots:\n", + "\n", + "1. The input fake sky has constant I/Q/U values at each pixel, and those are given in the plot subtitle.\n", + "\n", + "2. The plot is \"looking out\" from the telescope and the COSMO convention Q/U axes are drawn from this perspective.\n", + "\n", + "3. The focalplane frame X axis is parallel to the local coordinate system meridian and pointed \"South\". In other words, the detector gamma angle is exactly equal to the \"alpha\" angle from the local meridian.\n", + "\n", + "4. There are 4 detectors at the boresight, and their actual and expected values are given (which should be the same). I am using a calibration factor of $C = 0.5$, so the total response is $0.5[I + q_{weight} * Q + u_{weight} * U]$. The q/u weights are defined in this document above and in the code for the cases with / without a HWP. The cross polar response is set to zero in this test.\n", + "\n", + "Each row represents a different HWP state (including no HWP at all). Each column represents different input map values of $I = 1$, $Q = 1$, $U = 1$, and $I = Q = U = 1$" + ] + }, + { + "cell_type": "markdown", + "id": "54", + "metadata": {}, + "source": [ + "![No HWP](pointing_weights_figs/hwp_row_none.png)\n", + "![HWP 0.0](pointing_weights_figs/hwp_row_0.0.png)\n", + "![HWP 45.0](pointing_weights_figs/hwp_row_45.0.png)\n", + "![HWP 90.0](pointing_weights_figs/hwp_row_90.0.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.pdf b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.pdf new file mode 100644 index 000000000..1b23e9179 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.png b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.png new file mode 100644 index 000000000..5b6a11c2c Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.png differ diff --git a/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.svg b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.svg new file mode 100644 index 000000000..efc758aee --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3.svg @@ -0,0 +1,1024 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + East + South + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COSMO (HEALPix) Conventions + + North + North + South + South + East + East + Z + z + x + y + Y + X + Y + Y + X + X + + –U + + –U + + +Q + + +Q + + +U + + +U + + –Q + + –Q + Coordinate Sphere + Tangent plane, looking inward + Tangent plane, looking outward + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + aa + diff --git a/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3_original.svg b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3_original.svg new file mode 100644 index 000000000..88087d07a --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/COSMO_Pol_Conventions_v3_original.svg @@ -0,0 +1,552 @@ + + + + + + + + + + + + + + + + + + + + + + East + South + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f + q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COSMO (HEALPix) Conventions + + North + North + South + South + East + East + Z + z + x + y + Y + X + Y + Y + X + X + + –U + + –U + + +Q + + +Q + + +U + + +U + + –Q + + –Q + Coordinate Sphere + Tangent plane, looking inward + Tangent plane, looking outward + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + y + y + + diff --git a/docs/docs/design/pointing_weights_figs/IAU_Pol_Conventions_v3.svg b/docs/docs/design/pointing_weights_figs/IAU_Pol_Conventions_v3.svg new file mode 100644 index 000000000..174f811f9 --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/IAU_Pol_Conventions_v3.svg @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + South + East + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + d + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + North + North + Z + z + x + y + Y + Y + X + X + North + East + + +U + + +Q + + –U + + –Q + Y + X + North + East + + +U + + +Q + + –U + + –Q + + + + + + + + + + + + + + + + + + + IAU Conventions + Coordinate Sphere + Tangent plane, looking inward + Tangent plane, looking outward + + + y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/design/pointing_weights_figs/beam_hwp.svg b/docs/docs/design/pointing_weights_figs/beam_hwp.svg new file mode 100644 index 000000000..af454078d --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/beam_hwp.svg @@ -0,0 +1,1040 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Detector Frame("South")Detector X(PolarizationDirection)Pxx Beam FrameFocalplane XDirection(Dxx Beam Frame)HWP AxisDetector Y(Detector ZOut of Page)(Tangent plane, looking inward) + + + + + + + + + + + + + + + + + + + + + + + aw +gHWPgDET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +POLψUVψ diff --git a/docs/docs/design/pointing_weights_figs/det_frame.pdf b/docs/docs/design/pointing_weights_figs/det_frame.pdf new file mode 100644 index 000000000..12dbffcae Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/det_frame.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/det_frame.png b/docs/docs/design/pointing_weights_figs/det_frame.png new file mode 100644 index 000000000..1ac0de499 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/det_frame.png differ diff --git a/docs/docs/design/pointing_weights_figs/det_frame.svg b/docs/docs/design/pointing_weights_figs/det_frame.svg new file mode 100644 index 000000000..019f4ee1c --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/det_frame.svg @@ -0,0 +1,1221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Detector Frame Relative toOther Coordinate Frames("South" in skycoordinates)(Detector X)Focalplane XDirection("Down" inElevation)HWP AxisDetector Y(Detector ZOut of Page)(Tangent plane, looking inward) + + + + + + + + + + + + + + + + + + + + + + + aw +gHWPgDET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Detector Frame Relative toOther Coordinate Frames("South" in skycoordinates)(Detector X)Focalplane XDirection("Down" inElevation)HWP AxisDetector Y(Detector ZInto Page)(Tangent plane, looking outward)awgHWPgDET diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_0.0.pdf b/docs/docs/design/pointing_weights_figs/hwp_row_0.0.pdf new file mode 100644 index 000000000..146fc5fa1 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_0.0.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_0.0.png b/docs/docs/design/pointing_weights_figs/hwp_row_0.0.png new file mode 100644 index 000000000..989cb9763 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_0.0.png differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_45.0.pdf b/docs/docs/design/pointing_weights_figs/hwp_row_45.0.pdf new file mode 100644 index 000000000..74b791705 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_45.0.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_45.0.png b/docs/docs/design/pointing_weights_figs/hwp_row_45.0.png new file mode 100644 index 000000000..87ed6b69b Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_45.0.png differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_90.0.pdf b/docs/docs/design/pointing_weights_figs/hwp_row_90.0.pdf new file mode 100644 index 000000000..aa632bfca Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_90.0.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_90.0.png b/docs/docs/design/pointing_weights_figs/hwp_row_90.0.png new file mode 100644 index 000000000..62d3364c4 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_90.0.png differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_none.pdf b/docs/docs/design/pointing_weights_figs/hwp_row_none.pdf new file mode 100644 index 000000000..6c79049d1 Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_none.pdf differ diff --git a/docs/docs/design/pointing_weights_figs/hwp_row_none.png b/docs/docs/design/pointing_weights_figs/hwp_row_none.png new file mode 100644 index 000000000..682b80edf Binary files /dev/null and b/docs/docs/design/pointing_weights_figs/hwp_row_none.png differ diff --git a/docs/docs/design/pointing_weights_figs/montage_stokes.sh b/docs/docs/design/pointing_weights_figs/montage_stokes.sh new file mode 100755 index 000000000..ede4796e6 --- /dev/null +++ b/docs/docs/design/pointing_weights_figs/montage_stokes.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# To update figures: +# Copy the output hwp-static_* files from the ops_stokes_weights unit +# test output into this directory, and then run this script. + +den=300 +geom="576x576" + +for hwp in "none" "0.0" "45.0" "90.0"; do + infiles="" + for case in "I1-Q0-U0" "I0-Q1-U0" "I0-Q0-U1" "I1-Q1-U1"; do + infiles="${infiles} -density ${den} -geometry ${geom} hwp-static_${hwp}_test-0-0_${case}.pdf" + done + montage -tile 4x1 ${infiles} "hwp_row_${hwp}.pdf" +done + + diff --git a/docs/docs/design/process_model.md b/docs/docs/design/process_model.md new file mode 100644 index 000000000..533267f37 --- /dev/null +++ b/docs/docs/design/process_model.md @@ -0,0 +1,12 @@ +# Processing Model + + + +The highest-level control of the workflow is done by the user, often by writing +a small Python script or notebook (some examples are included). Such scripts +make use of TOAST functionality for distributing data and then call built-in or +custom operators to simulate and / or process the timestream data. + + +::: toast.ops.Operator + diff --git a/docs/docs/develop/index.md b/docs/docs/develop/index.md new file mode 100644 index 000000000..7594246b1 --- /dev/null +++ b/docs/docs/develop/index.md @@ -0,0 +1,11 @@ +# Overview + +This section is designed to document various aspects of the development process. + +## Coding Standards + + +## Git Workflow + + +## Deployment Process diff --git a/docs/docs/index.md b/docs/docs/index.md new file mode 100644 index 000000000..2e2d82d32 --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1,48 @@ +# Introduction + +The Time-Ordered Astrophysics Scalable Tools (TOAST) package is a [software framework](https://en.wikipedia.org/wiki/Software_framework) +designed for simulation and reduction of data from telescope receivers which acquire +timestreams of individual detector responses. This type of instrumentation is often +used when observing wavelengths from the microwave through the far IR. Data from such +telescopes present unique challenges compared to images acquired in optical astronomy. +Timestreams of detector responses can be correlated in time due to the optical response +time of the detector and noise in the readout chain. Timestreams can be correlated +between detectors due to thermal fluctuations, readout cross-talk, atmospheric emission +and pickup from the ground. These correlations motivate us to process larger pieces of +data simultaneously in order to extract the best possible estimate of the underlying +signal coming from space, while reducing statistical errors and removing sources of +systematic error. To accommodate the collective processing of large data sets, TOAST +has been designed to scale to high concurrency to handle the largest data volumes. +TOAST workflows have been run on systems ranging from a laptop up to 150,000 cores of +the largest HPC system at the NERSC computing center. The software has been developed +over the course of 15 years and three major revisions. + +The TOAST framework allows the user to build up a simulation and reduction workflow +composed of well tested and general tools, as well as custom operations specific to a +given experiment. TOAST provides modules for simulating sky signal, correlated +instrument noise, readout crosstalk, realistic atmospheric signal, beam asymmetries, +ground pickup, calibration errors, pointing errors, and more. For data reduction, the +package provides modules for a variety of time domain and spatial filters, simple binned +mapmaking, and a "generalized destriping" mapmaker which can regress templates from the +data to model the noise, gain drifts, and other contaminating signals. Along with these +built-in modules, experiments can create their own simulation and reduction modules to +build a workflow customized to a specific use case. + +The TOAST framework has been used in previous experiments, including the +[joint LFI/HFI Planck analysis](https://arxiv.org/abs/2007.04997). The TOAST framework +is one component of the data management tools being developed by the Simons Observatory. +TOAST is also part of the baseline plan for CMB-S4 simulation and reduction at HPC +centers such as NERSC and ALCF. + +## Specific Experiments + +If you are working with data from or simulations of one of these projects: + +- Planck +- LiteBIRD +- Simons Observatory +- CMB-S4 +- TolTEC + +Then there are additional software repositories you have access to that contain extra +TOAST classes and scripts for your experiment. diff --git a/docs/docs/install.md b/docs/docs/install.md new file mode 100644 index 000000000..0486cc249 --- /dev/null +++ b/docs/docs/install.md @@ -0,0 +1,10 @@ +# Installation + +In order to use TOAST and develop external custom classes, you can install +binary packages from conda-forge or PyPI. If you are working on the TOAST +package itself, there are several options for setting up a development +environment. + +## Binary Packages + +## Building from Source diff --git a/docs/docs/recipes/index.md b/docs/docs/recipes/index.md new file mode 100644 index 000000000..07dd0c5c7 --- /dev/null +++ b/docs/docs/recipes/index.md @@ -0,0 +1 @@ +# Overview diff --git a/docs/docs/reference/cli_tools.md b/docs/docs/reference/cli_tools.md new file mode 100644 index 000000000..cda6de1e6 --- /dev/null +++ b/docs/docs/reference/cli_tools.md @@ -0,0 +1,5 @@ +# Command Line Tools + +There are several command line helper tools included with TOAST... + + diff --git a/docs/docs/reference/data.md b/docs/docs/reference/data.md new file mode 100644 index 000000000..56a43af45 --- /dev/null +++ b/docs/docs/reference/data.md @@ -0,0 +1,17 @@ +# Data Containers + +TOAST uses several key classes for storing time ordered data, instrument properties, and pixel domain data. TOAST supports fully distributing time and pixel domain data across multiple nodes of a cluster or supercomputer. + +## Data Object + +::: toast.mpi.Comm + +::: toast.Data + +## Observation + +::: toast.observation.Observation + +Each `Observation` has its own instrument model (see Instrument Model section). + + diff --git a/docs/docs/reference/global.md b/docs/docs/reference/global.md new file mode 100644 index 000000000..6ea25a054 --- /dev/null +++ b/docs/docs/reference/global.md @@ -0,0 +1,10 @@ +# Global Settings + +The toast module has several global settings that can be configured at runtime +with environment variables or by explicitly calling functions in the package. + +::: toast + +## Accelerator Use + +TOAST supports the use of JAX for offloading some operations. To enable this... diff --git a/docs/docs/reference/instrument.md b/docs/docs/reference/instrument.md new file mode 100644 index 000000000..7f4afe0bc --- /dev/null +++ b/docs/docs/reference/instrument.md @@ -0,0 +1,18 @@ +# Instrument Model + +For each Observation (see Data Containers), a unique instrument model is specified. This includes the set of detectors, their properties, and other metadata about the overall telescope. + +::: toast.instrument.Site + +::: toast.instrument.GroundSite + +::: toast.instrument.SpaceSite + +::: toast.instrument.Bandpass + +::: toast.instrument.Focalplane + +::: toast.instrument.Telescope + +::: toast.instrument.Session + diff --git a/docs/docs/reference/map_domain.md b/docs/docs/reference/map_domain.md new file mode 100644 index 000000000..3dded6ec7 --- /dev/null +++ b/docs/docs/reference/map_domain.md @@ -0,0 +1,20 @@ +# Map Domain + +Internally, map domain objects (hit maps, signal maps, pixel noise covariances, etc) are +stored in a distributed fashion. This enables each process to only store a subset of +the sky pixels, which saves memory for large maps at high resolution. `PixelData` +objects have methods to read and write HDF5 and FITS format files. + +::: toast.pixels.PixelDistribution + +::: toast.pixels.PixelData + +Map domain objects can be saved to and loaded from different formats on disk depending +on the pixelization. Healpix maps support both FITS and a more performant HDF5 format. +Maps in WCS flat projections only support FITS formats. + +::: toast.pixels_io_healpix.read_healpix +::: toast.pixels_io_healpix.write_healpix + +::: toast.pixels_io_wcs.write_wcs +::: toast.pixels_io_wcs.read_wcs diff --git a/docs/docs/reference/reduction.md b/docs/docs/reference/reduction.md new file mode 100644 index 000000000..b2e139f8f --- /dev/null +++ b/docs/docs/reference/reduction.md @@ -0,0 +1,120 @@ +# Analysis Tools + +## Utilities + +::: toast.ops.Delete +::: toast.ops.Reset + +::: toast.ops.Copy +::: toast.ops.Combine + +::: toast.ops.CalibrateDetectors + +::: toast.ops.MemoryCounter +::: toast.ops.Statistics + +::: toast.ops.Pipeline + +::: toast.ops.RunSpt3g + +## Flagging + +::: toast.ops.AzimuthIntervals +::: toast.ops.FlagIntervals + +::: toast.ops.FlagSSO + +::: toast.ops.SimpleDeglitch +::: toast.ops.SimpleJumpCorrect + +::: toast.ops.FillGaps + +## Filtering + +### Polynomial Filters + +::: toast.ops.CommonModeFilter +::: toast.ops.PolyFilter +::: toast.ops.PolyFilter2D + +### Specialized Filters + +::: toast.ops.GroundFilter + +::: toast.ops.MitigateCrossTalk + +### Half Wave Plate Tools + +::: toast.ops.HWPSynchronousModel +::: toast.ops.HWPFilter + +::: toast.ops.Demodulate +::: toast.ops.StokesWeightsDemod + +## Pointing Matrix + +::: toast.ops.PointingDetectorSimple + +::: toast.ops.PixelsHealpix +::: toast.ops.PixelsWCS + +::: toast.ops.StokesWeights + +## Scan Strategy Characterization + +::: toast.ops.CadenceMap +::: toast.ops.CrossLinking + +## Noise Estimation + +::: toast.ops.NoiseEstim +::: toast.ops.FitNoiseModel +::: toast.ops.FlagNoiseFit + +::: toast.ops.SignalDiffNoiseModel + +## Map Making + +### Utilities + +::: toast.ops.BuildPixelDistribution +::: toast.ops.BuildHitMap +::: toast.ops.BuildInverseCovariance +::: toast.ops.BuildNoiseWeighted +::: toast.ops.CovarianceAndHits +::: toast.ops.NoiseWeight + +::: toast.ops.BinMap + +### Observation Matrices + +::: toast.ops.ObsMat +::: toast.ops.FilterBin +::: toast.ops.combine_observation_matrix +::: toast.ops.coadd_observation_matrix + +### Template Regression + +::: toast.templates.Amplitudes +::: toast.templates.AmplitudesMap +::: toast.templates.Template + +::: toast.templates.Offset +::: toast.templates.Periodic +::: toast.templates.SubHarmonic +::: toast.templates.Fourier2D +::: toast.templates.GainTemplate + +::: toast.ops.TemplateMatrix +::: toast.ops.SolveAmplitudes + +### High Level Tools + +::: toast.ops.Calibrate +::: toast.ops.MapMaker + +### External Tools + +::: toast.ops.Madam +::: toast.ops.madam_params_from_mapmaker + diff --git a/docs/docs/reference/simulation.md b/docs/docs/reference/simulation.md new file mode 100644 index 000000000..5fbcfcf78 --- /dev/null +++ b/docs/docs/reference/simulation.md @@ -0,0 +1,117 @@ +# Simulation Tools + +TOAST contains a variety of Operators and other tools for simulating telescope +observations and different detector signals. + +## Simulated Observing + +When designing new telescopes or observing strategies the TOAST scheduler can be used to +create schedule files that can be passed to the `SimGround` and `SimSatellite` +operators. + +### Ground-Based Schedules + +#### Sky Patches + +!!! note "To-Do" + We can't add docs for the patch types, because they have no docstrings... + + + +#### Scheduling Utilities + +!!! note "To-Do" + Do we want more of the low-level tools here? + +::: toast.schedule_sim_ground.parse_patches +::: toast.schedule_sim_ground.build_schedule + +#### Generating the Schedule + +::: toast.schedule_sim_ground.run_scheduler + +### Space-Based Schedules + +Generating schedules for a satellite is conceptually simpler due to the constraints on spacecraft dynamics. + +::: toast.schedule_sim_satellite.create_satellite_schedule + +### Creating Observations + +::: toast.ops.SimGround +::: toast.ops.SimSatellite + +## Sky Signals + +These operators generate detector data containing sources of power from outside the Earth's atmosphere. + +::: toast.ops.SimDipole + +### Beam-Convolved Sky + +::: toast.ops.SimConviqt +::: toast.ops.SimTEBConviqt +::: toast.ops.SimWeightedConviqt +::: toast.ops.SimTotalconvolve + +### Scanning a Healpix Map + +::: toast.ops.ScanHealpixMap +::: toast.ops.ScanHealpixMask +::: toast.ops.InterpolateHealpixMap + +### Scanning a WCS Projected Map + +::: toast.ops.ScanWCSMap +::: toast.ops.ScanWCSMask + +### Scanning an Arbitrary Map + +::: toast.ops.ScanMap +::: toast.ops.ScanMask +::: toast.ops.ScanScale + +### Point Sources + +::: toast.ops.SimCatalog + + +## Terrestrial Signals + +These operators generate detector signal from the Earth's atmosphere and other sources of power outside a ground-based telescope. + +::: toast.ops.WeatherModel +::: toast.ops.SimAtmosphere + +::: toast.ops.SimScanSynchronousSignal + +## Instrument Signals + +These operators simulate instrumental effects from sources of power inside the telescope and receiver. + +::: toast.ops.DefaultNoiseModel +::: toast.ops.ElevationNoise +::: toast.ops.SimNoise +::: toast.ops.CommonModeNoise + +::: toast.ops.TimeConstant + +::: toast.ops.InjectCosmicRays + +::: toast.ops.GainDrifter +::: toast.ops.GainScrambler + +::: toast.ops.PerturbHWP + + + +::: toast.ops.CrossTalk + +::: toast.ops.YieldCut + diff --git a/docs/docs/reference/tod_io.md b/docs/docs/reference/tod_io.md new file mode 100644 index 000000000..afb8756e4 --- /dev/null +++ b/docs/docs/reference/tod_io.md @@ -0,0 +1,11 @@ +# Data Formats + +TOAST has a built-in data format for storing compressed time ordered data on disk in one +or more HDF5 files. + +::: toast.ops.SaveHDF5 +::: toast.ops.LoadHDF5 + +::: toast.ops.SaveSpt3g +::: toast.ops.LoadSpt3g + diff --git a/docs/docs/reference/workflow.md b/docs/docs/reference/workflow.md new file mode 100644 index 000000000..4e59bc5a4 --- /dev/null +++ b/docs/docs/reference/workflow.md @@ -0,0 +1,5 @@ +# Workflows + +TOAST "workflows" are just python scripts which use some helper functions for setting up one or more `Operator` instances using configuration information from external files or the commandline. Not every python script using TOAST needs to make use of these tools and be a formal "workflow". For example, one can write a python script which instantiates operators as you need them with all parameters specified in the script and no information supplied from the command line. Using the workflow tools are most useful when a standard simulation / processing sequence will be run on multiple datasets with different options. + + diff --git a/docs/docs/toast_logo_small.png b/docs/docs/toast_logo_small.png new file mode 100644 index 000000000..3b7f7e13e Binary files /dev/null and b/docs/docs/toast_logo_small.png differ diff --git a/docs/docs/tutorials/data_model.ipynb b/docs/docs/tutorials/data_model.ipynb new file mode 100644 index 000000000..06c30efbb --- /dev/null +++ b/docs/docs/tutorials/data_model.ipynb @@ -0,0 +1,1161 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "toc-hr-collapsed": false + }, + "source": [ + "# Tutorial: Overview\n", + "\n", + "This tutorial will walk through the basic data containers used in TOAST and how they can be constructed and accessed. The goal is to provide an overview " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TOAST interactive startup\n", + "import toast.interactive\n", + "%load_ext toast.interactive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%toast -p 1 -a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Built-in modules\n", + "import sys\n", + "import os\n", + "import datetime\n", + "\n", + "# External modules\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import astropy.units as u\n", + "\n", + "# TOAST\n", + "import toast\n", + "from toast.tests import helpers\n", + "from toast.observation import default_values as defaults\n", + "\n", + "# Display inline plots\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Runtime Environment\n", + "\n", + "The `toast` module can be influenced by a few environment variables, which must be set **before** importing `toast`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "help(toast)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "toast?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can get the current TOAST runtime configuration from the \"Environment\" class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = toast.Environment.get()\n", + "print(env)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The logging level can be changed by either setting the `TOAST_LOGLEVEL` environment variable to one of the supported levels (`VERBOSE`, `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`) or by using the `set_log_level()` method of the `Environment` class. The maximum number of threads is controlled by the standard `OMP_NUM_THREADS` environment variable." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "toc-hr-collapsed": true + }, + "source": [ + "# Data Model\n", + "\n", + "The basic data model in a toast workflow consists of a set of `Observation` instances, each of which is associated with a `Focalplane` on a `Telescope`. Note that a Focalplane instance is probably just a sub-set of detectors on the actual physical focalplane. These detectors must be co-sampled and likely have other things in common (for example, they are on the same wafer or are correlated in some other way). For this notebook, we will manually create these objects, but usually these will be loaded / created by some experiment-specific function.\n", + "\n", + "MPI is completely optional in TOAST, although it is required to achieve good parallel performance on systems with many (e.g. 4 or more) cores. Most of the parallelism in TOAST is MPI process-based, not threaded. In this section we show how interactive use of TOAST can be done without any reference to MPI. In a separate notebook in this directory we show how to make use of distributed data and operations in parallel workflows.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Start by making a fake focalplane\n", + "\n", + "from toast.instrument_sim import (\n", + " fake_hexagon_focalplane,\n", + " plot_focalplane,\n", + ")\n", + "\n", + "focalplane_pixels = 7 # (hexagonal, pixel zero at center)\n", + "field_of_view = 5.0 * u.degree\n", + "sample_rate = 10.0 * u.Hz\n", + "\n", + "focalplane = fake_hexagon_focalplane(\n", + " n_pix=focalplane_pixels,\n", + " width=field_of_view,\n", + " fwhm=1.0 * u.degree,\n", + " sample_rate=sample_rate,\n", + " epsilon=0.0,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Make a plot of this focalplane layout.\n", + "\n", + "detpolcol = {\n", + " x: \"red\" if x.endswith(\"A\") else \"blue\" for x in focalplane.detectors\n", + "}\n", + "\n", + "plot_focalplane(\n", + " focalplane=focalplane,\n", + " width=1.3 * field_of_view,\n", + " height=1.3 * field_of_view,\n", + " show_labels=True,\n", + " pol_color=detpolcol\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now make a fake telescope\n", + "\n", + "telescope = toast.Telescope(name=\"fake\", focalplane=focalplane, site=toast.SpaceSite(name=\"L2\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have a fake telescope created, we can create an observation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Make an empty observation\n", + "\n", + "samples = 10\n", + "\n", + "ob = toast.Observation(\n", + " toast.Comm(),\n", + " telescope, \n", + " name=\"2020-07-31_A\", \n", + " n_samples=samples\n", + ")\n", + "\n", + "print(ob)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we see our observation simply has the starting information we passed to the constructor. Next we will discuss the 3 types of data objects that can be stored in an Observation: detector data products, shared telescope data, and arbitrary metadata." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Metadata\n", + "\n", + "By default, the observation is empty. You can add arbitrary metadata to the observation- it acts just like a dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hk = {\n", + " \"Temperature 1\": np.array([1.0, 2.0, 3.0]),\n", + " \"Other Sensor\": 1.2345\n", + "}\n", + "\n", + "ob[\"housekeeping\"] = hk\n", + "\n", + "print(ob)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Metadata like this is not synchronized in any way between processes. A user or Operator can put any keys here to store small data objects." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Detector Data\n", + "\n", + "Detector data has some unique properties that we often want to leverage in our analyses. Each process has some detectors and some time slice of the observation. In the case of a single process like this example, all the data is local. Before using data we need to create it within the empty Observation. Here we create a \"signal\" object for the detectors. The detector data is accessed under the `detdata` attribute of the observation:\n", + "\n", + "\n", + "**FIXME: talk about naming conventions**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we create and initialize to zero some detector data named \"signal\". This has one value per sample per detector and each value is a 64bit float." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.detdata.create(\"signal\", dtype=np.float64)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(ob.detdata)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(ob.detdata[\"signal\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can create other types of detector data, and there is some shortcut notation that can be used to create detector data objects from existing arrays. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This takes an existing N_detector x N_sample array and creates from that\n", + "\n", + "some_data = 3.0 * np.ones(\n", + " (\n", + " len(ob.local_detectors), \n", + " ob.n_local_samples\n", + " ),\n", + " dtype=np.float32\n", + ")\n", + "\n", + "ob.detdata[\"existing_signal\"] = some_data\n", + "print(ob.detdata[\"existing_signal\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This takes one detectors-worth of data and replicates it to all detectors\n", + "# while creating a new data object.\n", + "\n", + "ob.detdata[\"replicated\"] = 5 * np.ones(ob.n_local_samples, dtype=np.int32)\n", + "print(ob.detdata[\"replicated\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# You can also create detector data objects from a dictionary\n", + "# of single-detector arrays\n", + "other = dict()\n", + "for i, d in enumerate(ob.local_detectors):\n", + " other[d] = i * np.ones(ob.n_local_samples, dtype=np.int32)\n", + "\n", + "ob.detdata[\"other_signal\"] = other\n", + "print(ob.detdata[\"other_signal\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default you will get detector data with one element per sample and float64 dtype. However, you can specify the shape of each detector sample:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example of data with different shape\n", + "\n", + "ob.detdata.create(\"pointing\", sample_shape=(4,), dtype=np.float32)\n", + "print(ob.detdata[\"pointing\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Details of Detector Data\n", + "\n", + "In the commands above we created named data objects and each one seems to contain an array for each detector. However, this container actually allocates memory in a single block, and you can slice the object both in the detector and sample direction. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Access one detector by name\n", + "ob.detdata[\"signal\"][\"D0A-150\"] = np.arange(samples, dtype=np.float64)\n", + "\n", + "# Access one detector by index\n", + "ob.detdata[\"signal\"][1] = 10.0 * np.arange(samples, dtype=np.float64)\n", + "\n", + "# Slice by both detector and sample\n", + "ob.detdata[\"signal\"][[\"D2A-150\", \"D2B-150\"], 0:2] = 5.0\n", + "\n", + "print(ob.detdata[\"signal\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Access the whole thing as a 2D array\n", + "print(ob.detdata[\"signal\"][:])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Shared Data\n", + "\n", + "Many types of data are common to multiple detectors. Some examples would be telescope pointing, timestamps, other sensor data, etc. When running in parallel we want to have just one copy of this data per node in order to save memory. The shared data is accessed under the \"shared\" attribute of the observation. For this serial notebook, you will not need to worry about the details of communicators, but when running in parallel it becomes important. \n", + "For this serial notebook, the `shared` attribute will look very much like a dictionary of numpy arrays. See the \"parallel\" intro notebook for more examples of using shared data when each observation is distributed across a grid of processes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create some time stamps by assigning from an existing array on one process.\n", + "# When running with multiple processes, this syntax has extra communication.\n", + "ob.shared[\"times\"] = np.arange(ob.n_local_samples, dtype=np.float64)\n", + "print(ob.shared[\"times\"])\n", + "\n", + "# Create and initialize to zero some boresight quaternions\n", + "ob.shared.create_column(\n", + " \"boresight_radec\", shape=(ob.n_local_samples, 4), dtype=np.float64\n", + ")\n", + "print(ob.shared[\"boresight_radec\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see that the data objects are a special \"MPIShared\" object from the [`pshmem`](https://pypi.org/project/pshmem/) package. Shared data objects can be read with slicing notation just like normal numpy arrays:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(ob.shared[\"boresight_radec\"][:])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, they are intended to be \"write once\", \"read many\" objects. You cannot simply assign data to them. The reason is that the data is replicated across nodes and so setting array values must be a collective operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nullquat = np.array([0.0, 0.0, 0.0, 1.0])\n", + "full_data = np.tile(nullquat, ob.n_local_samples).reshape((-1, 4))\n", + "\n", + "# In the serial case, simple assignment works just like array assignment\n", + "ob.shared[\"boresight_radec\"][:] = full_data\n", + "\n", + "# When running with MPI, the set() method avoids some communication\n", + "ob.shared[\"boresight_radec\"].set(full_data, fromrank=0)\n", + "\n", + "print(ob.shared[\"boresight_radec\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Intervals\n", + "\n", + "Each `Observation` may contain one or more \"interval lists\" which act as a global (within the observation) list of time / sample ranges where some feature of the data is constant. Interval lists support sample-wise inversion, intersection and union operations using the standard python bitwise operators (`^`, `&`, and `|`).\n", + "\n", + "Intervals are **not** intended to act as individual sample quality flags. Per-sample flags should be created either as a shared timestream (for flags common to all detectors) or as a detector data object (for per-detector flags). Intervals can be used to represent things changing less frequently, for example: left or right moving telescope scans, satellite repointing maneuvers, calibration measurements, etc.\n", + "\n", + "A single `Interval` consists of a time and a (local) sample range:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "? toast.Interval" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The observation starts with no lists of intervals\n", + "\n", + "ob.intervals" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To add a new interval list, use the `create()` method. Remember, in this notebook we have only one process, so do not have to worry about which process this information is coming from:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "help(ob.intervals.create)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we create one list of intervals. We specify the time ranges and the local array of timestamp values. Inside the code, the timestamps are used to convert these input time ranges into `Interval` objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.intervals.create(\"good\", [(1.5, 3.5), (4.5, 6.), (7., 8.5)], ob.shared[\"times\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now there is one interval list in the observation\n", + "\n", + "print(ob.intervals)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The create method converted the time ranges into actual Interval instances:\n", + "\n", + "print(ob.intervals[\"good\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now create another list of intervals:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.intervals.create(\"stable\", [(0.5, 2.5), (3.5, 5.), (6., 7.5)], ob.shared[\"times\"])\n", + "print(ob.intervals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As mentioned before, we can combine these in different ways:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.intervals[\"stable-and-not-good\"] = ob.intervals[\"stable\"] & ~ob.intervals[\"good\"]\n", + "\n", + "print(ob.intervals)\n", + "print(ob.intervals[\"stable-and-not-good\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.intervals[\"not-stable-or-not-good\"] = ~ob.intervals[\"stable\"] | ~ob.intervals[\"good\"]\n", + "\n", + "print(ob.intervals)\n", + "print(ob.intervals[\"not-stable-or-not-good\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Views\n", + "\n", + "Typically when defining data intervals in the last section it is because you want to do something with only the data falling in those sample ranges. Each observation has the ability to provide a \"view\" into the detector and shared data given by a previously defined interval list. Views are created on the fly on first access and are deleted automatically if the underlying interval is deleted. First, examine a view of the \"good\" interval list we defined in the previous section:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(ob.view[\"good\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The string represention of a view is just a list of sample slices. However, the real power is that we can get a view of any of the observation `detdata` or `shared` objects. For example, we could get a view of the detector `signal` data. Recall that the full data for this is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.detdata[\"signal\"][:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A view of the signal data falling in the \"good\" intervals is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.view[\"good\"].detdata[\"signal\"][:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This view is a list of arrays which have sliced the data in the time direction. These are **not** copies- they provide read/write access to underlying buffer. If you are doing many operations with a view it is easier to name it something else:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sng = ob.view[\"stable-and-not-good\"]\n", + "sng.detdata[\"signal\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, we can use a view to assign data to a subset of the full samples:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sng.detdata[\"signal\"] = 7.0\n", + "\n", + "print(ob.detdata[\"signal\"][:])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access shared data as well with this view, but it is read-only from the view (the `set()` method of the shared objects or a collective assignment must be used to modify shared data):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ob.view[\"good\"].shared[\"boresight_radec\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sng.shared[\"boresight_radec\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data Container\n", + "\n", + "The `Observation` instances discussed previously are usually stored as a list inside a top-level container class called `Data`. This class also stores the TOAST MPI communicator information. For this serial example you can just instantiate an empty `Data` class and add things to the observation list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = toast.Data()\n", + "\n", + "print(data)\n", + "\n", + "print(data.obs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Obviously this `Data` object has no observations yet. We'll fix that in the next section!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Processing Model\n", + "\n", + "The TOAST processing model consists of `Operator` class instances running in a sequence on a subset of data. These sequences could be nested within other sequences (see the `Pipeline` operator below).\n", + "\n", + "The Operator base class defines the interfaces for operators working on data. Operators are configured by defining class traits (attributes) which can be set during construction. An operator has an `exec()` method that works with Data objects (potentially just a subset of the data). Operators also have a `finalize()` method which is designed to do any final calculations after all passes through the timestream data are done. We will start by looking at the SimSatellite operator to simulate fake telescope scan strategies for a generic satellite. We can always see the options and default values by using the standard help function or the '?' command:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from toast import ops\n", + "from toast.schedule_sim_satellite import create_satellite_schedule\n", + "\n", + "?ops.SimSatellite" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can instantiate a class directly by overriding some defaults:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "simsat = ops.SimSatellite(\n", + " num_observations=2, \n", + " observation_time=5 * u.minute,\n", + ")\n", + "\n", + "print(simsat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are using multi instances of an operator in your pipeline with different configurations, then you should also pass a unique \"name\" to the constructor. This allows keeping the operators distinct when using config files (see more below):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "other_simsat = ops.SimSatellite(\n", + " name=\"other_simsat\",\n", + " num_observations=2, \n", + " observation_time=5 * u.minute,\n", + ")\n", + "\n", + "print(other_simsat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the operator is constructed, the parameters can be changed directly. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "simsat.telescope = telescope\n", + "simsat.num_observations = 3\n", + "\n", + "# Create a schedule for our simulated observing\n", + "simsat.schedule = create_satellite_schedule(\n", + " mission_start=datetime.datetime(2023, 2, 23),\n", + " observation_time=24 * u.hour,\n", + " gap_time=0 * u.second,\n", + " num_observations=1,\n", + " prec_period=90 * u.minute,\n", + " spin_period=10 * u.minute,\n", + ")\n", + "\n", + "print(simsat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now we have an `Operator` that is ready to use. This particular operator creates observations from scratch with telescope properties generated and stored. We can create an empty `Data` object and then run this operator on it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This is equivalent to single call to \"exec()\" with all processes,\n", + "# and then a call to \"finalize()\".\n", + "\n", + "simsat.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this trivial case, we use the `apply()` method of the operator, which simply calls `exec()` once and then `finalize()`. When running a more complicated pipeline, the `exec()` method might be called multiple times on different detector sets (for example) before calling `finalize()`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pipelines\n", + "\n", + "TOAST includes a special operator (the `Pipeline` class), which is designed to run other operators (including other Pipeline instances. The purpose of this operator is to run sequences of other operators over sets of detectors to reduce the memory cost of intermediate products and / or to group together operators that support the use of accelerators to avoid memory copies to the host system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "? ops.Pipeline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As an example, we can create two simple operators and put them in a pipeline:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "simsat = ops.SimSatellite(\n", + " num_observations=2, \n", + " observation_time=5 * u.minute,\n", + " telescope=telescope,\n", + " schedule = create_satellite_schedule(\n", + " mission_start=datetime.datetime(2023, 2, 23),\n", + " observation_time=24 * u.hour,\n", + " gap_time=0 * u.second,\n", + " num_observations=1,\n", + " prec_period=90 * u.minute,\n", + " spin_period=10 * u.minute,\n", + " ),\n", + ")\n", + "\n", + "default_noise = ops.DefaultNoiseModel()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pipe = ops.Pipeline(\n", + " operators=[simsat, default_noise]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can start with an empty Data object and run the pipeline on it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = toast.Data()\n", + "\n", + "pipe.apply(data)\n", + "\n", + "print(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see here that the same satellite simulation was run, and then a default noise model (using the focalplane properties in each observation) was created." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configuration of Operators\n", + "\n", + "Operators are configured through class traits which can be passed as keyword arguments to the constructor. We can also dump information about these traits (name, type, help string) to an intermediate config dictionary and then write that to files in TOML or JSON format. These config dictionaries can also be used to instantiate operators directly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import toast.config as tc\n", + "\n", + "import tempfile\n", + "from pprint import PrettyPrinter\n", + "\n", + "pp = PrettyPrinter(indent=1)\n", + "\n", + "tmpdir = tempfile.mkdtemp()\n", + "toml_file = os.path.join(tmpdir, \"test.toml\")\n", + "yaml_file = os.path.join(tmpdir, \"test.yaml\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As an example, we can take a previous operator and look at the \"round trip\" from class or instance, to a config dictionary, to a file, and back into creating a new operator instance from that:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This gives us the config for an existing instance\n", + "\n", + "conf = other_simsat.get_config()\n", + "pp.pprint(conf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This gives us the default config values for a class\n", + "\n", + "default_conf = ops.SimSatellite.get_class_config()\n", + "pp.pprint(default_conf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tc.dump_toml(toml_file, conf)\n", + "tc.dump_yaml(yaml_file, conf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can see what this config looks like dumped to TOML and YAML:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!cat {toml_file}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!cat {yaml_file}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then we can load the config back in to a dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "newconf = tc.load_config(yaml_file)\n", + "pp.pprint(newconf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can create new instances of operators from this config dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "run = toast.traits.create_from_config(newconf)\n", + "print(run)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we access our new operator and use it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "new_simsat = run.operators.other_simsat\n", + "print(new_simsat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running the Test Suite\n", + "\n", + "TOAST includes extensive tests built in to the package. Running all of them takes some time, but you can also run just one test by specifying the name of the file in the toast/tests directory (without the \".py\" extension):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import toast.tests\n", + "\n", + "# Run just a couple simple tests in toast/tests/env.py\n", + "toast.tests.run(\"env\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now run **ALL** the (serial) tests\n", + "# toast.tests.run()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/docs/tutorials/index.md b/docs/docs/tutorials/index.md new file mode 100644 index 000000000..a312735a3 --- /dev/null +++ b/docs/docs/tutorials/index.md @@ -0,0 +1,5 @@ +# Overview + +These tutorials give a brief introduction to particular aspects of the TOAST +tools. For more complete examples that go into further details, see the "Cook +Book" / Recipes. diff --git a/docs/docs/tutorials/operators.ipynb b/docs/docs/tutorials/operators.ipynb new file mode 100644 index 000000000..f40d09f88 --- /dev/null +++ b/docs/docs/tutorials/operators.ipynb @@ -0,0 +1,157 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "toc-hr-collapsed": false + }, + "source": [ + "# Tutorial: Operators\n", + "\n", + "This tutorial provides an overview of TOAST Operator classes, which are the primary mechanism for passing data containers through simulation and reduction operations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TOAST interactive startup\n", + "import toast.interactive\n", + "%load_ext toast.interactive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%toast -p 1 -a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Built-in modules\n", + "import sys\n", + "import os\n", + "\n", + "# External modules\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import astropy.units as u\n", + "\n", + "# TOAST\n", + "import toast\n", + "from toast.tests import helpers\n", + "\n", + "# Display inline plots\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Get our MPI world rank to use later when only one process needs to do\n", + "# plotting, etc.\n", + "comm, procs, rank = toast.get_world()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Output directory.\n", + "out_dir = \"workflows_output\"\n", + "if rank == 0:\n", + " if not os.path.isdir(out_dir):\n", + " os.mkdir(out_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Observing Schedule\n", + "\n", + "For a simulation, we need to create an observing schedule.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import toast.schedule_sim_ground\n", + "\n", + "schfile = os.path.join(out_dir, \"schedule.txt\")\n", + "schopts = [\n", + " \"--equalize-area\", \"--equalize-time\", \"--site-lat\", \"-22.958064\",\n", + " \"--site-lon\", \"-67.786222\", \"--site-alt\", \"5200\", \"--site-name\",\n", + " \"ATACAMA\", \"--telescope\", \"SAT\", \"--patch-coord\", \"C\", \"--el-min\",\n", + " \"55\", \"--el-max\", \"70\", \"--sun-el-max\", \"90\", \"--sun-avoidance-angle\",\n", + " \"45\", \"--moon-avoidance-angle\", \"45\", \"--start\", \"2023-11-01 00:00:00\",\n", + " \"--stop\", \"2023-11-02 00:00:00\", \"--gap-s\", \"300\", \"--gap-small\", \"0\",\n", + " \"--ces-max-time\", \"3600\", \"--fp-radius\", \"0\", \"--out\", schfile, \n", + " \"--elevations-deg\", \"50,55,60,65\", \"--patch\",\n", + " \"DEC-050..-030_RA+000.000..+011.613,1.000,0.000,-30.000,11.613,-50.000\",\n", + "]\n", + "if rank == 0:\n", + " toast.schedule_sim_ground.run_scheduler(opts=schopts)\n", + "if comm is not None:\n", + " comm.barrier()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Interactive timestream plotting. Only if we are running\n", + "# with one process.\n", + "# if procs == 1:\n", + "# w = toast.widgets.ObservationWidget(data.obs[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/docs/tutorials/sim_ground.ipynb b/docs/docs/tutorials/sim_ground.ipynb new file mode 100644 index 000000000..13fc33c19 --- /dev/null +++ b/docs/docs/tutorials/sim_ground.ipynb @@ -0,0 +1,1352 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "toc-hr-collapsed": false + }, + "source": [ + "# Tutorial: Simulated Ground Telescopes\n", + "\n", + "This tutorial focuses on simulating data from a ground-based telescope. We first create a fake telescope with a synthetic focalplane located in Chile. Then we create a synthetic observing schedule and use that to scan the sky. Later notebooks make use of helper functions that create generic focalplanes, but in this example we use low-level functions to customize things a bit more. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Optionally change logging level\n", + "import os\n", + "os.environ[\"TOAST_LOGLEVEL\"] = \"INFO\"\n", + "# This is needed before importing toast, and should\n", + "# match the value passed to the '-t' option of %toast\n", + "os.environ[\"OMP_NUM_THREADS\"] = \"4\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TOAST interactive startup\n", + "import toast.interactive\n", + "%load_ext toast.interactive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%toast -p 1 -t 4 -a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Built-in modules\n", + "import sys\n", + "import os\n", + "import re\n", + "import datetime\n", + "import shutil\n", + "\n", + "# External modules\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.image import imread\n", + "import astropy.units as u\n", + "from astropy.table import Row, QTable\n", + "import healpy as hp\n", + "\n", + "# TOAST\n", + "import toast\n", + "import toast.schedule_sim_ground\n", + "from toast.instrument_sim import plot_focalplane\n", + "from toast.tests import helpers\n", + "from toast.observation import default_values as defaults\n", + "\n", + "# Display inline plots\n", + "%matplotlib inline\n", + "from IPython.display import Image\n", + "from IPython.display import display" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# MPI communicator\n", + "world, procs, rank = toast.mpi.get_world()\n", + "comm = helpers.create_comm(world, single_group=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Output directory for this tutorial\n", + "topdir = \"out_sim_ground\"\n", + "if rank == 0 and os.path.exists(topdir):\n", + " shutil.rmtree(topdir)\n", + "out_dir = helpers.create_outdir(world, topdir=topdir)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper Functions\n", + "\n", + "Here are a few functions we will use later in the notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_dets(obs, d_start=0, d_end=None, s_start=0, s_end=None, view=None, signal=defaults.det_data):\n", + " \"\"\"Plot some detectors in an observation.\n", + " \n", + " Args:\n", + " obs (Observation): The observation\n", + " d_start (int): The starting local detector index to plot.\n", + " d_end (int): The local detector index limit to plot.\n", + " s_start (int): The starting sample index to plot.\n", + " s_end (int): The sample index limit to plot\n", + " view (str): The optional intervals to overplot.\n", + " signal (str): The detdata name to plot.\n", + " \"\"\"\n", + " slc = slice(s_start, s_end, 1)\n", + "\n", + " fig = plt.figure(dpi=100, figsize=(18, 12))\n", + " ax = fig.add_subplot(2, 1, 1, aspect=\"auto\")\n", + " plt.gca().set_prop_cycle(None)\n", + " for idet, det in enumerate(obs.select_local_detectors(flagmask=defaults.det_mask_nonscience)):\n", + " if idet < d_start:\n", + " continue\n", + " if d_end is not None and idet >= d_end:\n", + " continue\n", + " ax.plot(\n", + " obs.shared[defaults.times].data[slc], \n", + " obs.detdata[signal][det, slc], \n", + " '-',\n", + " label=det,\n", + " )\n", + " ax.legend(loc=\"best\")\n", + " \n", + " ax = fig.add_subplot(2, 1, 2, aspect=\"auto\")\n", + " \n", + " if view is not None:\n", + " inview = np.zeros_like(obs.shared[defaults.shared_flags].data[slc])\n", + " begin = [x.first for x in obs.intervals[view]]\n", + " end = [x.last+1 for x in obs.intervals[view]]\n", + " for b, e in zip(begin, end):\n", + " inview[b:e] = 1\n", + " ax.plot(\n", + " obs.shared[defaults.times].data[slc], \n", + " inview, \n", + " '-',\n", + " color=\"red\",\n", + " label=f\"View {view}\",\n", + " )\n", + " ax.plot(\n", + " obs.shared[defaults.times].data[slc], \n", + " obs.shared[defaults.shared_flags].data[slc], \n", + " '-',\n", + " color=\"black\",\n", + " label=\"Shared Flags\",\n", + " )\n", + " \n", + " plt.gca().set_prop_cycle(None)\n", + " for idet, det in enumerate(obs.select_local_detectors(flagmask=defaults.det_mask_nonscience)):\n", + " if idet < d_start:\n", + " continue\n", + " if d_end is not None and idet >= d_end:\n", + " continue\n", + " ax.plot(\n", + " obs.shared[defaults.times].data[slc], \n", + " obs.detdata[defaults.det_flags][det, slc], \n", + " '-',\n", + " label=det,\n", + " )\n", + " ax.legend(loc=\"best\") \n", + " plt.show()\n", + " plt.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_scanning(obs, s_start=0, s_end=None):\n", + " slc = slice(s_start, s_end, 1)\n", + " times = obs.shared[defaults.times].data[slc]\n", + " az = obs.shared[defaults.azimuth].data[slc]\n", + " el = obs.shared[defaults.elevation].data[slc]\n", + " \n", + " fig = plt.figure(dpi=100, figsize=(18, 12))\n", + " ax = fig.add_subplot(2, 1, 1, aspect=\"auto\")\n", + " ax.plot(times, az, label=\"Azimuth\")\n", + " ax.set_xlabel(\"Posix Timestamps\")\n", + " ax.set_ylabel(\"Azimuth\")\n", + " ax = fig.add_subplot(2, 1, 2, aspect=\"auto\")\n", + " ax.plot(times, el, label=\"Elevation\")\n", + " ax.set_xlabel(\"Posix Timestamps\")\n", + " ax.set_ylabel(\"Elevation\")\n", + " plt.show()\n", + " plt.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_noise_model(model, model_fit=None, d_start=0, d_end=None):\n", + " fig = plt.figure(dpi=100, figsize=(18, 12))\n", + " ax = fig.add_subplot(1, 1, 1)\n", + " plt.gca().set_prop_cycle(None)\n", + " plot_max = 0\n", + " plot_min = 1e100\n", + " for idet, det in enumerate(model.detectors):\n", + " if idet < d_start:\n", + " continue\n", + " if d_end is not None and idet >= d_end:\n", + " continue\n", + " freq = model.freq(det).to_value(u.Hz)\n", + " psd = model.psd(det).to_value(u.K**2 * u.s)\n", + " plot_min = min(plot_min, np.amin(psd))\n", + " plot_max = max(plot_max, np.amax(psd))\n", + " ax.loglog(\n", + " freq,\n", + " psd,\n", + " label=det,\n", + " )\n", + " if model_fit is not None:\n", + " # Also plot the fit\n", + " plt.gca().set_prop_cycle(None)\n", + " for idet, det in enumerate(model.detectors):\n", + " if idet < d_start:\n", + " continue\n", + " if d_end is not None and idet >= d_end:\n", + " continue\n", + " freq = model_fit.freq(det)\n", + " psd = model_fit.psd(det)\n", + " ax.loglog(\n", + " freq.to_value(u.Hz),\n", + " psd.to_value(u.K**2 * u.s),\n", + " label=f\"{det} Fit\",\n", + " )\n", + " freq = model.freq(model.detectors[0])\n", + " \n", + " ax.set_xlim(freq[0].to_value(u.Hz), freq[-1].to_value(u.Hz))\n", + " ax.set_ylim(0.9 * plot_min, 1.1 * plot_max)\n", + " ax.set_xlabel(\"Frequency [Hz]\")\n", + " ax.set_ylabel(\"PSD [K$^2$ / Hz]\")\n", + " ax.legend(loc=\"best\")\n", + " plt.show()\n", + " plt.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Fake Telescope\n", + "\n", + "We create just a small number of detectors here since we are running this notebook serially. If you use more processes you can increase the number of detectors on the focalplane. First create a `Site` for telescope:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "site = toast.instrument.GroundSite(\"atacama\", \"-22:57:30\", \"-67:47:10\", 5200.0 * u.meter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will create a focalplane consisting of three rhombus wafers packed into a hexagon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fp_fwhm = 30.0 * u.arcmin\n", + "\n", + "focalplane = toast.instrument_sim.fake_rhombihex_focalplane(\n", + " n_pix_rhombus=16,\n", + " width=8.0 * u.degree,\n", + " gap=0 * u.radian,\n", + " sample_rate=10.0 * u.Hz,\n", + " epsilon=0.0,\n", + " fwhm=fp_fwhm,\n", + " bandcenter=150 * u.GHz,\n", + " bandwidth=20 * u.GHz,\n", + " psd_net=300.0 * u.uK * np.sqrt(1 * u.second),\n", + " psd_fmin=1.0e-5 * u.Hz,\n", + " psd_alpha=1.0,\n", + " psd_fknee=0.05 * u.Hz,\n", + " fwhm_sigma=0.0 * u.arcmin,\n", + " bandcenter_sigma=0 * u.GHz,\n", + " bandwidth_sigma=0 * u.GHz,\n", + " random_seed=123456,\n", + ")\n", + "fov = focalplane.field_of_view" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Look at the table of detector properties\n", + "focalplane.detector_data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Make a plot of this focalplane layout.\n", + "detpolcol = {\n", + " x: \"red\" if re.match(r\".*A-.*\", x) is not None else \"blue\" for x in focalplane.detectors\n", + "}\n", + "\n", + "if rank == 0:\n", + " plot_focalplane(\n", + " focalplane=focalplane,\n", + " width=1.2 * fov,\n", + " height=1.2 * fov,\n", + " show_labels=True,\n", + " pol_color=detpolcol\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Atmospheric Monitoring\n", + "\n", + "In order to provide a channel to monitor the atmospheric water content, we add a single detector at the boresight whose bandpass is centered on the water line at 183GHz. We make a copy of the previous detector table and construct a new focalplane." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "det_props = QTable(focalplane.detector_data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copy the last row into a dictionary\n", + "atm_det = {x: det_props[-1][x] for x in det_props.colnames}\n", + "print(atm_det)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Modify the atmosphere detector properties\n", + "atm_det[\"name\"] = \"ATM0\"\n", + "atm_det[\"quat\"] = np.array([0.0, 0.0, 0.0, 1.0])\n", + "atm_det[\"bandcenter\"] = 183.0 * u.GHz\n", + "atm_det[\"bandwidth\"] = 20.0 * u.GHz\n", + "det_props.add_row(atm_det)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Build a new focalplane with the updated table\n", + "full_fp = toast.instrument.Focalplane(\n", + " detector_data=det_props,\n", + " sample_rate=focalplane.sample_rate,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "detpolcol = {\n", + " x: \"red\" if re.match(r\".*A-.*\", x) is not None else \"blue\" for x in full_fp.detectors\n", + "}\n", + "\n", + "if rank == 0:\n", + " plot_focalplane(\n", + " focalplane=full_fp,\n", + " width=1.2 * fov,\n", + " height=1.2 * fov,\n", + " show_labels=True,\n", + " pol_color=detpolcol\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can check the top-hat bandpasses in this Focalplane. We just look at the first normal detector and the last detector which is the atmosphere monitor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if rank == 0:\n", + " fig = plt.figure(dpi=100, figsize=(12, 6))\n", + " ax = fig.add_subplot(1, 1, 1, aspect=\"auto\")\n", + " for det in [full_fp.detectors[0], full_fp.detectors[-1]]:\n", + " freq = full_fp.bandpass.freqs(det)\n", + " bpass = full_fp.bandpass.bandpass(det)\n", + " ax.plot(\n", + " freq, \n", + " bpass, \n", + " '-',\n", + " label=det,\n", + " )\n", + " ax.set_xlim(100e9, 250e9)\n", + " ax.legend(loc=\"best\")\n", + " plt.show()\n", + " plt.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally we build our telescope with this updated focalplane and Site" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "telescope = toast.instrument.Telescope(\"telescope\", focalplane=full_fp, site=site)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulated Observing Schedule\n", + "\n", + "Now that we have a telescope, we create an observing schedule." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "schedule = None\n", + "\n", + "if rank == 0:\n", + " tdir = out_dir\n", + " if tdir is None:\n", + " tdir = tempfile.mkdtemp()\n", + "\n", + " sch_file = os.path.join(tdir, \"ground_schedule.txt\")\n", + " toast.schedule_sim_ground.run_scheduler(\n", + " opts=[\n", + " \"--site-name\",\n", + " telescope.site.name,\n", + " \"--telescope\",\n", + " telescope.name,\n", + " \"--site-lon\",\n", + " \"{}\".format(telescope.site.earthloc.lon.to_value(u.degree)),\n", + " \"--site-lat\",\n", + " \"{}\".format(telescope.site.earthloc.lat.to_value(u.degree)),\n", + " \"--site-alt\",\n", + " \"{}\".format(telescope.site.earthloc.height.to_value(u.meter)),\n", + " \"--patch\",\n", + " \"bossn,1,-180,15,-140,2\",\n", + " \"--start\",\n", + " \"2025-02-21 00:00:00\",\n", + " \"--stop\",\n", + " \"2025-02-23 00:00:00\",\n", + " \"--out\",\n", + " sch_file,\n", + " \"--equalize-time\",\n", + " \"--patch-coord\",\n", + " \"C\",\n", + " \"--el-min\",\n", + " \"40\",\n", + " \"--el-max\",\n", + " \"70\",\n", + " \"--sun-el-max\",\n", + " \"90\",\n", + " \"--sun-avoidance-angle\",\n", + " \"30\",\n", + " \"--moon-avoidance-angle\",\n", + " \"0\",\n", + " \"--ces-max-time\",\n", + " \"36000\",\n", + " \"--fp-radius\",\n", + " \"0\",\n", + " \"--boresight-angle-step\",\n", + " \"180\",\n", + " \"--boresight-angle-time\",\n", + " \"1440\",\n", + " \"--time-step-s\",\n", + " \"600\",\n", + " \"--lock-az-range\",\n", + " \"--elevations\",\n", + " \"40,50,60,70\",\n", + " ]\n", + " )\n", + " schedule = toast.schedule.GroundSchedule()\n", + " schedule.read(sch_file)\n", + " if out_dir is None:\n", + " shutil.rmtree(tdir)\n", + "if world is not None:\n", + " schedule = world.bcast(schedule, root=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulated Observing\n", + "\n", + "Now we use this schedule to create some fake observing with our telescope. This will generate the data containers with boresight pointing, but the detector data is still zero." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Start with an empty data container\n", + "data = toast.Data(comm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Populate observations according to the schedule and telescope.\n", + "sim_ground = toast.ops.SimGround(\n", + " telescope=telescope,\n", + " weather=\"atacama\",\n", + " detset_key=\"pixel\",\n", + " schedule=schedule,\n", + " median_weather=True, # no longer random weather, but less chance of an outlier\n", + ")\n", + "sim_ground.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print out the result.\n", + "data.info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if rank == 0:\n", + " plot_scanning(data.obs[0], s_start=0, s_end=2000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulated Detector Data\n", + "\n", + "Now we will simulate several components of our detector data. Before doing that, we set up some operators that compute our detector pointing and response on the sky (the \"pointing matrix\"). In TOAST, the pointing matrix is split into the pixelization of detector samples and the Stokes weights (response to I/Q/U/V on the sky)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Detector Pointing\n", + "\n", + "There are 3 types of operators that define the detector pointing. The first is the geometric offset from the boresight coordinate frame to the detector coordinate frame. In the simplest case this is just a quaternion for each detector (stored in the focalplane table). Once the geometric detector pointing is computed, the pixelization on the sky is specified by a separate operator. Finally, the response of the detector to incoming Stokes parameters is given by another operator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Geometric detector pointing from boresight frame to detector frame. We define these\n", + "# for both horizontal and equatorial coordinates, since we need the detector pointing\n", + "# in horizontal coordinates for atmosphere simulation below.\n", + "\n", + "det_point_azel = toast.ops.PointingDetectorSimple(\n", + " boresight=defaults.boresight_azel,\n", + " quats=\"quats_azel\"\n", + ")\n", + "det_point_radec = toast.ops.PointingDetectorSimple(\n", + " boresight=defaults.boresight_radec,\n", + " quats=\"quats_radec\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Pixelization. Choose a coarse pixelization for this exercise since there is\n", + "# a small patch and only a few detectors.\n", + "\n", + "nside = 256\n", + "pixels_radec = toast.ops.PixelsHealpix(\n", + " nside=nside,\n", + " nest=True,\n", + " detector_pointing=det_point_radec,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Stokes weights. This just uses focalplane table properties to treat each detector\n", + "# as a linear polarizer with possibly some cross-polar response.\n", + "\n", + "weights_radec = toast.ops.StokesWeights(\n", + " mode=\"IQU\",\n", + " detector_pointing=det_point_radec,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pixel Distribution\n", + "\n", + "When working with sky data for both simulations and mapmaking, each process only stores pixels which are \"hit\" by the local detectors on that process. Computing this \"pixel distribution\" requires passing through the pointing. Normally this is done without saving the detector pointing (for memory considerations). In this notebook, we just compute the full detector pointing once at the beginning and save it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pixels_radec.apply(data)\n", + "weights_radec.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pix_dist = toast.ops.BuildPixelDistribution(\n", + " pixel_dist=\"pixel_dist\",\n", + " pixel_pointing=pixels_radec,\n", + ")\n", + "pix_dist.apply(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Synthetic Sky\n", + "\n", + "In order to have some kind of sky signal in our data, we generate a fake sky and scan that into timestreams." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "input_map_file = os.path.join(out_dir, \"fake_sky.fits\")\n", + "if rank == 0:\n", + " c_ell = helpers.fetch_nominal_cmb_cls(\n", + " out_file=os.path.join(os.path.dirname(out_dir), \"cl_nominal.txt\")\n", + " )\n", + " input_map_ring = hp.synfast(c_ell, nside, fwhm=fp_fwhm.to_value(u.radian))\n", + " input_map = 1.0e-6 * hp.reorder(input_map_ring, inp=\"RING\", out=\"NEST\")\n", + " hp.write_map(input_map_file, input_map, nest=True)\n", + " hp.mollview(input_map[0], nest=True, min=-0.01, max=0.01)\n", + " hp.gnomview(\n", + " input_map[0], nest=True, min=-0.01, max=0.01, rot=(200.156, 8.466), reso=4.0, xsize=1600\n", + " )\n", + " hp.mollview(input_map[1], nest=True, min=-0.0002, max=0.0002)\n", + " hp.gnomview(\n", + " input_map[1], nest=True, min=-0.0002, max=0.0002, rot=(200.156, 8.466), reso=4.0, xsize=1600\n", + " )\n", + " hp.mollview(input_map[2], nest=True, min=-0.0002, max=0.0002)\n", + " hp.gnomview(\n", + " input_map[2], nest=True, min=-0.0002, max=0.0002, rot=(200.156, 8.466), reso=4.0, xsize=1600\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Scan the map\n", + "scan_map = toast.ops.ScanHealpixMap(\n", + " file=input_map_file,\n", + " pixel_pointing=pixels_radec,\n", + " stokes_weights=weights_radec,\n", + ")\n", + "scan_map.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the last few detectors\n", + "if rank == 0:\n", + " plot_dets(data.obs[0], d_start=90, d_end=None, s_start=0, s_end=2000, view=\"scanning\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instrumental Noise\n", + "\n", + "We create a trivial noise model using nominal parameters from the focalplane table and then use this noise model to simulate timestreams." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nominal_noise = toast.ops.DefaultNoiseModel()\n", + "nominal_noise.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot this nominal noise model for the last few detectors\n", + "if rank == 0:\n", + " plot_noise_model(\n", + " data.obs[0][nominal_noise.noise_model],\n", + " model_fit=None,\n", + " d_start=50,\n", + " d_end=None\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim_noise = toast.ops.SimNoise(\n", + " noise_model=nominal_noise.noise_model,\n", + ")\n", + "sim_noise.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the last few detectors\n", + "if rank == 0:\n", + " plot_dets(data.obs[0], d_start=90, d_end=None, s_start=0, s_end=2000, view=\"scanning\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the \"atmospheric monitor\" detector does not look much different here, since we have only simulated detector noise." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ground Pickup\n", + "\n", + "The ground and environment around the telescope may produce different loading as a function of azimuth as the telescope scans. This kind of signal is one of several possible \"scan synchronous signals\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ground_pickup = toast.ops.SimScanSynchronousSignal(\n", + " detector_pointing=det_point_azel,\n", + " scale=0.001 * u.K,\n", + ")\n", + "ground_pickup.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the last few detectors\n", + "if rank == 0:\n", + " plot_dets(data.obs[0], d_start=90, d_end=None, s_start=0, s_end=2000, view=\"scanning\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulated Atmosphere\n", + "\n", + "Now we will simulate a 3D atmospheric slab moving in front of the telescope and integrate each detector along the line of site and over its bandpass. In order to do this, we have to define an operator which knows how to compute detector pointing in Az/El coordinates. This just uses the boresight pointing and the detector quaternion rotations from the boresight to compute detector pointing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim_atm = toast.ops.SimAtmosphere(\n", + " detector_pointing=det_point_azel,\n", + " add_loading=True,\n", + " lmin_center=0.001 * u.m,\n", + " lmin_sigma=0.0001 * u.m,\n", + " lmax_center=1.0 * u.m,\n", + " lmax_sigma=0.1 * u.m,\n", + " xstep=20 * u.m,\n", + " ystep=20 * u.m,\n", + " zstep=20 * u.m,\n", + " zmax=200 * u.m,\n", + " gain=4e-5,\n", + " wind_dist=1000 * u.m,\n", + ")\n", + "sim_atm.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the last few normal detectors\n", + "if rank == 0:\n", + " plot_dets(data.obs[0], d_start=90, d_end=96, s_start=0, s_end=2000, view=\"scanning\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the atmosphere monitor\n", + "if rank == 0:\n", + " plot_dets(data.obs[0], d_start=96, d_end=None, s_start=0, s_end=2000, view=\"scanning\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we see that the atmospheric monitor has substantially more power from the 183GHz water line." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Map Making\n", + "\n", + "First we want to flag the atmosphere monitor channel so that it is not considered \"science\" data for mapmaking purposes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for ob in data.obs:\n", + " ob.update_local_detector_flags({\"ATM0\": defaults.det_mask_processing})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Filtering\n", + "\n", + "Since we are using the template regression / destriping mapmaker below, we want to do minimal filtering of the timestreams." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "toast.ops.CommonModeFilter(\n", + " redistribute=False,\n", + " regress=True,\n", + ").apply(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Noise Estimation\n", + "\n", + "The original noise estimate (used above to simulate instrument noise) only captures the nominal readout and detector noise sources. For map making we will treat the timestream as noise-dominated and estimate the noise model directly from the timestream. First, create a raw, binned estimate of the PSD in each detector:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Estimate noise\n", + "estim = toast.ops.NoiseEstim(\n", + " out_model=\"noise_estimate\",\n", + " lagmax=100,\n", + " nbin_psd=32,\n", + " nsum=1,\n", + ")\n", + "estim.apply(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This raw estimate can produce undesired effects if we use it directly in mapmaking. Instead, we first fit an analytic 1/f noise model to these." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Compute a 1/f fit to this\n", + "noise_fitter = toast.ops.FitNoiseModel(\n", + " noise_model=estim.out_model,\n", + " out_model=\"fit_noise_model\",\n", + ")\n", + "noise_fitter.apply(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot this nominal noise model for the last few detectors\n", + "if rank == 0:\n", + " plot_noise_model(\n", + " data.obs[0][estim.out_model],\n", + " model_fit=data.obs[0][noise_fitter.out_model],\n", + " d_start=90,\n", + " d_end=None\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Binning Operator\n", + "\n", + "A central piece of the mapmaking is the \"binning\" of timestreams into maps. This process accumulates the \"noise weighted map\" and then multiplies this by the diagonal pixel covariance:\n", + "\n", + "$$\n", + "\\text{Binned Map} = \\left(P^T N^{-1} P\\right)^{-1} P^T N^{-1} d\n", + "$$\n", + "\n", + "You can see from this that in addition to the input timestream data we need the estimated noise model and the pointing matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set up binning operator for solving\n", + "binner = toast.ops.BinMap(\n", + " pixel_dist=pix_dist.pixel_dist,\n", + " pixel_pointing=pixels_radec,\n", + " stokes_weights=weights_radec,\n", + " noise_model=noise_fitter.out_model,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Template Matrix\n", + "\n", + "The TOAST mapmaker is a \"generalized destriper\" that solves for \"template amplitudes\". These templates represent anything in the time ordered data which is not fixed on the sky or simply white noise. For this example, we will use 2 templates. One to model the scan synchronous signal and one to model the 1/f noise (including the atmosphere)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The Offset template models 1/f noise as a stepwise function, which\n", + "# is the same as a \"classic\" destriper.\n", + "\n", + "tmpl_offset = toast.templates.Offset(\n", + " times=defaults.times,\n", + " noise_model=noise_fitter.out_model,\n", + " step_time=1.0 * u.second,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Build a template matrix with our templates.\n", + "\n", + "tmatrix = toast.ops.TemplateMatrix(\n", + " templates=[tmpl_offset],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Making the Map\n", + "\n", + "Now we are ready to instantiate the mapmaker operator. Note that if we do not specify the template matrix, then this will just produce a binned map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "map_maker = toast.ops.MapMaker(\n", + " name=\"mapmaker\",\n", + " binning=binner,\n", + " template_matrix=tmatrix,\n", + " solve_rcond_threshold=1.0e-1,\n", + " map_rcond_threshold=1.0e-1,\n", + " iter_min=200,\n", + " iter_max=300,\n", + " write_hits=True,\n", + " write_map=True,\n", + " write_binmap=True,\n", + " write_cov=False,\n", + " write_invcov=False,\n", + " write_rcond=True,\n", + " output_dir=out_dir,\n", + " keep_solver_products=True, # We set this to True so we can plot solved template amplitudes later\n", + ")\n", + "map_maker.apply(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now plot the output maps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The output filenames will be based on the name of the mapmaker operator\n", + "out_root = os.path.join(out_dir, map_maker.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Helper functions to plot all the maps\n", + "\n", + "def plot_maps(\n", + " root,\n", + " range_I=(-0.01, 0.01),\n", + " range_Q=(-0.0002, 0.0002),\n", + " range_U=(-0.0002, 0.0002),\n", + " max_hits=1000,\n", + " truth=None\n", + "):\n", + " cmap = \"viridis\"\n", + " gnomres = 8.0\n", + " gnomrot = (199.5, 8.3)\n", + " xsize = 800\n", + " \n", + " hits_file = f\"{root}_hits.fits\"\n", + " rcond_file = f\"{root}_rcond.fits\"\n", + " binmap_file = f\"{root}_binmap.fits\"\n", + " map_file = f\"{root}_map.fits\"\n", + "\n", + " # Load hits\n", + " hits = hp.read_map(hits_file, field=None, nest=True)\n", + " goodhits = hits > 0\n", + " badhits = np.logical_not(goodhits)\n", + "\n", + " # Load rcond\n", + " rcond = hp.read_map(rcond_file, field=None, nest=True)\n", + " rcond[badhits] = hp.UNSEEN\n", + "\n", + " # Maps\n", + " maps = hp.read_map(map_file, field=None, nest=True)\n", + " binmaps = hp.read_map(binmap_file, field=None, nest=True)\n", + " resid = None\n", + " resid_bin = None\n", + " if truth is not None:\n", + " truth_maps = hp.read_map(truth, field=None, nest=True)\n", + " resid = list()\n", + " resid_bin = list()\n", + " for i in range(3):\n", + " resid.append(np.array(maps[i]) - truth_maps[i])\n", + " resid_bin.append(np.array(binmaps[i]) - truth_maps[i])\n", + " for i in range(3):\n", + " maps[i][badhits] = hp.UNSEEN\n", + " binmaps[i][badhits] = hp.UNSEEN\n", + " if truth is not None:\n", + " truth_maps[i][badhits] = hp.UNSEEN\n", + " resid[i][badhits] = hp.UNSEEN\n", + " resid_bin[i][badhits] = hp.UNSEEN\n", + "\n", + " # Plot hits and rcond\n", + " fig = plt.figure(dpi=100, figsize=(18, 12))\n", + " hp.gnomview(\n", + " map=hits,\n", + " fig=fig.number,\n", + " sub=(1, 2, 1),\n", + " rot=gnomrot,\n", + " xsize=xsize,\n", + " reso=gnomres,\n", + " nest=True,\n", + " cmap=cmap,\n", + " min=0,\n", + " max=max_hits,\n", + " title=\"Hits\",\n", + " )\n", + " hp.gnomview(\n", + " map=rcond,\n", + " fig=fig.number,\n", + " sub=(1, 2, 2),\n", + " rot=gnomrot,\n", + " xsize=xsize,\n", + " reso=gnomres,\n", + " nest=True,\n", + " cmap=cmap,\n", + " min=0,\n", + " max=0.5,\n", + " title=\"Inverse Condition Number\",\n", + " )\n", + " plt.show()\n", + " plt.close()\n", + "\n", + " # Plot maps\n", + " \n", + " plot_cols = 2\n", + " if truth is not None:\n", + " plot_cols = 4\n", + " plot_rows = 3\n", + " fig = plt.figure(dpi=100, figsize=(18, 18))\n", + " counter = 1\n", + " for row, (stokes, rng) in enumerate([(\"I\", range_I), (\"Q\", range_Q), (\"U\", range_U)]):\n", + " for mps, res, name in [(maps, resid, \"Destriped\"), (binmaps, resid_bin, \"Binned\")]:\n", + " hp.gnomview(\n", + " map=mps[row],\n", + " fig=fig.number,\n", + " sub=(plot_rows, plot_cols, counter),\n", + " rot=gnomrot,\n", + " xsize=xsize,\n", + " reso=gnomres,\n", + " nest=True,\n", + " cmap=cmap,\n", + " min=rng[0],\n", + " max=rng[1],\n", + " title=f\"{name} Stokes {stokes}\",\n", + " )\n", + " counter += 1\n", + " if truth is not None:\n", + " hp.gnomview(\n", + " map=res[row],\n", + " fig=fig.number,\n", + " sub=(plot_rows, plot_cols, counter),\n", + " rot=gnomrot,\n", + " xsize=xsize,\n", + " reso=gnomres,\n", + " nest=True,\n", + " cmap=cmap,\n", + " min=rng[0],\n", + " max=rng[1],\n", + " title=f\"{name} Stokes {stokes} Minus Input\",\n", + " )\n", + " counter += 1\n", + " plt.show()\n", + " plt.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_maps(out_root, truth=input_map_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The solved template amplitudes will usually have degeneracies (for example, the ground pickup across one left-right scan could also be interpreted as just 1/f noise). However, we are just concerned with capturing the degrees of freedom of the relevant non-sky signal content so that it does not contaminate the map. This is something to keep in mind as we plot the solved template amplitudes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write solved offset amplitudes\n", + "oamps = data[f\"{map_maker.name}_solve_amplitudes\"][tmpl_offset.name]\n", + "oroot = os.path.join(out_dir, f\"{map_maker.name}_offset\")\n", + "tmpl_offset.write(oamps, oroot)\n", + "\n", + "if rank == 0:\n", + " for ob in data.obs:\n", + " toast.templates.offset.plot(\n", + " f\"{oroot}_{ob.name}.h5\",\n", + " compare={x: ob.detdata[defaults.det_data][x, :] for x in ob.local_detectors},\n", + " out=f\"{oroot}_{ob.name}\",\n", + " xlim=(0, 1000),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index ae3f3d014..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. TOAST documentation master file, created by - sphinx-quickstart on Thu Apr 9 10:07:11 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - - -TOAST -============= - -Contents: - -.. toctree:: - :maxdepth: 2 - - intro.rst - changes.rst - install.rst - data.rst - operators.rst - pipelines.rst - utils.rst - nersc.rst - tutorial.rst - dev.rst - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/install.rst b/docs/install.rst deleted file mode 100644 index cef28f05d..000000000 --- a/docs/install.rst +++ /dev/null @@ -1,424 +0,0 @@ -.. _install: - -Installation -==================== - -TOAST is written in C++ and python3 and depends on several commonly available packages. -It also has some optional functionality that is only enabled if additional external -packages are available. The best installation method will depend on your specific -needs. We try to clarify the different options below. - -User Installation --------------------------- - -If you are using TOAST to build simulation and analysis workflows, including mixing -built-in functionality with your own custom tools, then you can use one of these methods -to get started. If you want to hack on the TOAST package itself, see the section -:ref:`devinstall`. - -If you want to use TOAST at NERSC, see :ref:`nersc`. - -Pip Binary Wheels -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you already have a newer Python3 (>= 3.6), then you can install pre-built TOAST -packages from PyPI. You should always use virtualenv or similar tools to manage your -python environments rather than pip-installing packages as root. - -On Ubuntu Linux, you should install these minimal packages:: - - apt update - apt install python3 python3-pip python3-venv - -On Redhat / Centos we need to take extra steps to install a recent python3:: - - yum update - yum install centos-release-scl - yum install rh-python36 - scl enable rh-python36 bash - -On MacOS, you can use homebrew or macports to install a recent python3. Now verify that -your python is at least 3.6:: - - python3 --version - -Next create a virtualenv (name it whatever you like):: - - python3 -m venv ${HOME}/cmb - -Now activate this environment:: - - source ${HOME}/cmb/bin/activate - -Within this virtualenv, update pip to the latest version. This is needed in order to -install more recent wheels from PyPI:: - - python3 -m pip install --upgrade pip - -Next, use pip to install toast and its requirements (note that the name of the package -is "toast-cmb" on PyPI):: - - pip install toast-cmb - -At this point you have toast installed and you can use it from serial scripts and -notebooks. If you want to enable effective parallelism with toast (useful if you -computer has many cores), then you need to install the mpi4py package. This package -requires MPI compilers (usually MPICH or OpenMPI). Your system may already have some -MPI compilers installed- try this:: - - which mpicc - mpicc -show - -If the mpicc command is not found, you should use your OS package manager to install the -development packages for MPICH or OpenMPI. Now you can install mpi4py:: - - pip install mpi4py - -For more details about custom installation options for mpi4py, read the `documentation -for that package `_. You can test your TOAST installation by running the unit test suite:: - - python -c 'import toast.tests; toast.tests.run()' - -And test running in parallel with:: - - mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' - -The runtime configuration of toast can also be checked with an included script:: - - toast_env_test.py - - -Conda Packages -~~~~~~~~~~~~~~~~~~~~~~ - -If you already use the conda python stack, then you can install TOAST and all of its -optional dependencies with the conda package manager. The conda-forge ecosystem allows -us to create packages that are built consistently with all their dependencies. If you -already have Anaconda / miniconda installed **and** it is a recent version, then skip -ahead to "activating the root environment below". - -If you are starting from scratch, we recommend following the `setup guidelines used by -conda-forge -`_, -specifically: - - 1. Install a "miniconda" base system (not the full Anaconda distribution). - - 2. Set the conda-forge channel to be the top priority package source, with strict ordering if available. - - 3. Leave the base system (a.k.a. the "root" environment) with just the bare minimum of packages. - - 4. Always create a new environment (i.e. not the base one) when setting up a python - stack for a particular purpose. This allows you to upgrade the conda base system in - a reliable way, and to wipe and recreate whole conda environments whenever needed. - -Here are the detailed steps of how you could do this from the UNIX shell, installing the -base conda system to ``${HOME}/conda``. First download the installer. For OS X you -would do:: - - curl -SL \ - https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh \ - -o miniconda.sh - -For Linux you would do this:: - - curl -SL \ - https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh \ - -o miniconda.sh - -Next we will run the installer. The install prefix should not exist previously:: - - bash miniconda.sh -b -p "${HOME}/conda" - -Now load this conda "root" environment:: - - source ${HOME}/conda/etc/profile.d/conda.sh - conda activate - -We are going to make sure to preferentially get packages from the conda-forge channel:: - - conda config --add channels conda-forge - conda config --set channel_priority strict - -Next, we are going to create a conda environment for a particular purpose (installing -TOAST). You can create as many environments as you like and install different packages -within them- they are independent. In this example, we will call this environment -"toast", but you can call it anything:: - - conda create -y -n toast - -Now we can activate our new (and mostly empty) toast environment:: - - conda activate toast - -Finally, we can install the toast package:: - - conda install python=3 toast - -Assuming this isthe only conda installation on your system, you can add the line -``source ${HOME}/conda/etc/profile.d/conda.sh`` to your shell resource file (usually -``~/.bashrc`` on Linux or ``~/.profile`` on OS X). You can read many articles on login -shells versus non-login shells and decide where to put this line for your specific use -case. - -Now you can always activate your toast environment with:: - - conda activate toast - -And leave that environment with:: - - conda deactivate - -If you want to use other packages with TOAST (e.g. Jupyter Lab), then you can activate -the toast environment and install them with conda. See the conda documentation for more -details on managing environments, installing packages, etc. - -If you want to use PySM with TOAST for sky simulations, you should install the ``pysm3`` -and ``libsharp`` packages. For example:: - - conda install pysm3 libsharp - -If you want to enable effective parallelism with toast, then you need to install the -mpi4py package:: - - conda install mpi4py - -As mentioned previously, you can test your TOAST installation by running the unit test -suite:: - - python -c 'import toast.tests; toast.tests.run()' - -And test running in parallel with:: - - mpirun -np 2 python -c 'import toast.tests; toast.tests.run()' - - -Something Else -~~~~~~~~~~~~~~~~~~~~~ - -If you have a custom install situation that is not met by the above solutions, then you -should follow the instructions below for a "Developer install". - - -.. _devinstall: - -Developer Installation ------------------------------ - -Here we will discuss several specific system configurations that are known to work. The -best one for you will depend on your OS and preferences. - -Ubuntu Linux -~~~~~~~~~~~~~~~~ - -You can install all but one required TOAST dependency using packages provided by the OS. -Note that this assumes a recent version of ubuntu (tested on 19.04):: - - apt update - apt install \ - cmake \ - build-essential \ - gfortran \ - libopenblas-dev \ - libmpich-dev \ - liblapack-dev \ - libfftw3-dev \ - libsuitesparse-dev \ - python3-dev \ - libpython3-dev \ - python3-scipy \ - python3-matplotlib \ - python3-healpy \ - python3-astropy \ - python3-pyephem - - -NOTE: if you are using another package on your system that requires OpenMPI, then you -may get a conflict installing libmpich-dev. In that case, just install libopenmpi-dev -instead. - -Next, download a `release of libaatm `_ and -install it. For example:: - - cd libaatm - mkdir build - cd build - cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/local \ - .. - make -j 4 - sudo make install - -You can also install it to the same prefix as TOAST or to a separate location for just -the TOAST dependencies. If you install it somewhere other than /usr/local then make -sure it is in your environment search paths (see the "installing TOAST" section). - -You can also now install the optional dependencies if you wish: - - * `libconviqt `_ for 4PI beam convolution. - * `libmadam `_ for optimized destriping mapmaking. - - -Other Linux -~~~~~~~~~~~~~~~~ - -If you have a different distro or an older version of Ubuntu, you should try to install -at least these packages with your OS package manager:: - - gcc - g++ - mpich or openmpi - lapack - fftw - suitesparse - python3 - python3 development library (e.g. libpython3-dev) - virtualenv (e.g. python3-virtualenv) - -Then you can create a python3 virtualenv, activate it, and then use pip to install these -packages:: - - pip install \ - numpy \ - scipy \ - matplotlib \ - healpy \ - astropy \ - pyephem \ - mpi4py - -Then install libaatm as discussed in the previous section. - -OS X with MacPorts -~~~~~~~~~~~~~~~~~~~~~~ - -.. todo:: Document using macports to get gcc and installing optional dependencies. - -OS X with Homebrew -~~~~~~~~~~~~~~~~~~~~~~~~ - -.. todo:: Document installing compiled dependencies and using a virtualenv. - -Full Custom Install with CMBENV -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The `cmbenv package `_ can generate an install script -that selectively compiles packages using specified compilers. This allows you to "pick -and choose" what packages are installed from the OS versus being built from source. See -the example configs in that package and the README. For example, there is an -"ubuntu-19.04" config that gets everything from OS packages but also compiles the -optional dependencies like libconviqt and libmadam. - - -Installing TOAST with CMake -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Decide where you want to install your development copy of TOAST. I recommend picking a -standalone directory somewhere. For this example, we will use -```${HOME}/software/toast``. This should **NOT** be the same location as your git -checkout. - -We want to define a small shell function that will load this directory into our -environment. You can put this function in your shell resource file (``~/.bashrc`` or -``~/.profile``):: - - load_toast () { - dir="${HOME}/software/toast" - export PATH="${dir}/bin:${PATH}" - export CPATH="${dir}/include:${CPATH}" - export LIBRARY_PATH="${dir}/lib:${LIBRARY_PATH}" - export LD_LIBRARY_PATH="${dir}/lib:${LD_LIBRARY_PATH}" - pysite=$(python3 --version 2>&1 | awk '{print $2}' | sed -e "s#\(.*\)\.\(.*\)\..*#\1.\2#") - export PYTHONPATH="${dir}/lib/python${pysite}/site-packages:${PYTHONPATH}" - } - -When installing dependencies, you may have chosen to install libaatm, libconviqt, and -libmadam into this same location. If so, load this location into your search paths now, -before installing TOAST:: - - load_toast - -TOAST uses CMake to configure, build, and install both the compiled code -and the python tools. Within the ``toast`` git checkout, run the following commands:: - - mkdir -p build && cd build - cmake -DCMAKE_INSTALL_PREFIX=$HOME/software/toast .. - make -j 2 install - -This will compile and install TOAST in the folder ``~/software/toast``. Now, every -time you want to use toast, just call the shell function:: - - load_toast - -If you need to customize the way TOAST gets compiled, the following -variables can be defined in the invocation to ``cmake`` using the -``-D`` flag: - -``CMAKE_INSTALL_PREFIX`` - Location where TOAST will be installed. (We used it in the example above.) - -``CMAKE_C_COMPILER`` - Path to the C compiler - -``CMAKE_C_FLAGS`` - Flags to be passed to the C compiler (e.g., ``-O3``) - -``CMAKE_CXX_COMPILER`` - Path to the C++ compiler - -``CMAKE_CXX_FLAGS`` - Flags to be passed to the C++ compiler - -``PYTHON_EXECUTABLE`` - Path to the Python interpreter - -``BLAS_LIBRARIES`` - Full path to the BLAS dynamical library - -``LAPACK_LIBRARIES`` - Full path to the LAPACK dynamical library - -``FFTW_ROOT`` - The install prefix of the FFTW package - -``AATM_ROOT`` - The install prefix of the libaatm package - -``SUITESPARSE_INCLUDE_DIR_HINTS`` - The include directory for SuiteSparse headers - -``SUITESPARSE_LIBRARY_DIR_HINTS`` - The directory containing SuiteSparse libraries - -See the top-level "platforms" directory for other examples of running CMake. - -Installing TOAST with Pip / setup.py -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The setup.py that comes with TOAST is just a wrapper around the cmake build system. You -can pass options to the underlying cmake call by setting environment variables prefixed -with "TOAST_BUILD_". For example, if you want to pass the location of the libaatm -installation to cmake when using setup.py, you can set the "TOAST_BUILD_AATM_ROOT" -environment variable. This will get translated to "-DAATM_ROOT" when cmake is invoked -by setup.py - -Testing the Installation ------------------------------ - -After installation, you can run both the compiled and python unit -tests. These tests will create an output directory named ``out`` in -your current working directory:: - - python -c "import toast.tests; toast.tests.run()" - - -Building the Documentation ------------------------------ - -You will need the two Python packages ``sphinx`` and -``sphinx_rtd_theme``, which can be installed using ``pip`` or -``conda`` (if you are running Anaconda):: - - cd docs && make clean && make html - -The documentation will be available in ``docs/_build/html``. diff --git a/docs/intro.rst b/docs/intro.rst deleted file mode 100644 index d8d18368f..000000000 --- a/docs/intro.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. _intro: - -Introduction -================================= - -TOAST is a `software framework `_ for -simulating and processing timestream data collected by telescopes. Telescopes which -collect data as timestreams rather than images give us a unique set of analysis -challenges. Detector data usually contains noise which is correlated in time as well as -sources of correlated signal from the instrument and the environment. Large pieces of -data must often be analyzed simultaneously to extract an estimate of the sky signal. -TOAST has evolved over several years. The current codebase contains an internal C++ -library to allow for optimization of some calculations, while the public interface is -written in Python. - -The TOAST framework contains: - - * Tools for distributing data among many processes - * Tools for performing operations on the local pieces of the data - * Generic operators for common processing tasks (filtering, pointing expansion, map-making) - * Basic classes for performing I/O in a limited set of formats - * Well-defined interfaces for adding custom I/O classes and processing operators - -The highest-level control of the workflow is done by the user, often by writing a small -Python "pipeline" script (some examples are included). Such pipeline scripts make use -of TOAST functions for distributing data and then call built-in or custom operators to -process the timestream data. - - -Support for Specific Experiments -------------------------------------- - -If you are a member of one of these projects: - - * Planck - * LiteBIRD - * Simons Array - * Simons Observatory - * CMB-S4 - -Then there are additional software repositories you have access to that contain extra -TOAST classes and scripts for processing data from your experiment. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml new file mode 100644 index 000000000..64fd9fcb9 --- /dev/null +++ b/docs/mkdocs.yml @@ -0,0 +1,84 @@ +site_name: TOAST + +theme: + name: "material" + logo: toast_logo_small.png + favicon: toast_logo_small.png + features: + - navigation.expand + - navigation.path + +plugins: + - search + - autorefs + - mkdocstrings: + handlers: + python: + options: + docstring_style: google + show_root_heading: true + heading_level: 2 + parameter_headings: false + members: true + filters: + - "!^_[^_]" + show_object_full_path: false + show_symbol_type_heading: true + show_symbol_type_toc: true + - mkdocs-jupyter: + execute: false + kernel_name: python3 + allow_errors: false + include_source: true + +nav: + - Introduction: index.md + - Installation: install.md + - Tutorials: + - tutorials/index.md + #- tutorials/interactive.ipynb + - tutorials/data_model.ipynb + #- tutorials/tod_ops.ipynb + #- tutorials/mapmaking.ipynb + #- tutorials/sim_instrument.ipynb + #- tutorials/sim_sky.ipynb + - Recipes: + - recipes/index.md + #- recipes/configuration.md + #- recipes/experiments.md + #- recipes/abstractions.md + - Design: + - design/overview.md + - design/data_model.md + - design/process_model.md + - design/pointing_weights.ipynb + - design/parallelism.md + #- design/workflows.md + - API Reference: + - reference/global.md + - reference/instrument.md + - reference/data.md + - reference/simulation.md + - reference/reduction.md + - reference/tod_io.md + - reference/map_domain.md + - reference/workflow.md + - reference/cli_tools.md + - For Developers: + - develop/index.md + #- develop/layout.md + #- develop/contributing.md + #- develop/deployment.md + +markdown_extensions: + - toc: + toc_depth: 2 + - pymdownx.arithmatex: + generic: true + - admonition + - pymdownx.details + - pymdownx.superfences + +extra_javascript: + - javascripts/mathjax.js + - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js diff --git a/docs/nersc.rst b/docs/nersc.rst deleted file mode 100644 index b41ac3c6d..000000000 --- a/docs/nersc.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. _nersc: - -Using TOAST at NERSC -==================== - -A recent version of TOAST is already installed at NERSC, along with all necessary dependencies. You can use this installation directly, or use it as the basis for your own development. - - -Module Files ---------------- - -To get access to the needed module files, add the machine-specific module file location to your search path:: - - module use /global/common/software/cmb/${NERSC_HOST}/default/modulefiles - -The `default` part of this path is a symlink to the latest stable installation. There are usually several older versions kept here as well. - -You can safely put the above line in your ~/.bashrc.ext inside the section for cori. It does not actually load anything into your environment. - - -Loading the Software ----------------------- - -To load the software do the following:: - - module load cmbenv - source cmbenv - -Note that the "source" command above is not "reversible" like normal module operations. This is required in order to activate the underlying conda environment. After running the above commands, TOAST and many other common software tools will be in your environment, including a Python3 stack. - - -Installing TOAST (Optional) -------------------------------- - -The cmbenv stack contains a recent version of TOAST, but if you want to build your own copy then you can use the cmbenv stack as a starting point. Here are the steps: - -1. Decide on the installation location. You should install software either to one of the project software spaces in `/global/common/software` or in your home directory. If you plan on using this installation for large parallel jobs, you should install to `/global/common/software`. - -2. Load the cmbenv stack. - -3. Go into your git checkout of TOAST and make a build directory:: - - cd toast - mkdir build - cd build - -4. Use the cori-intel platform file to build TOAST and install:: - - ../platforms/cori-intel.sh \ - -DCMAKE_INSTALL_PREFIX=/path/to/somewhere - make -j 4 install - -5. Set up a shell function in `~/.bashrc.ext` to load this into your environment search paths before the cmbenv stack:: - - load_toast () { - dir=/path/to/your/install - export PATH="${dir}/bin:${PATH}" - pysite=$(python3 --version 2>&1 | awk '{print $2}' | sed -e "s#\(.*\)\.\(.*\)\..*#\1.\2#") - export PYTHONPATH="${dir}/lib/python${pysite}/site-packages:${PYTHONPATH}" - } - -Now whenever you want to override the cmbenv TOAST installation you can just do:: - - load_toast diff --git a/docs/op_mapmaking.inc b/docs/op_mapmaking.inc deleted file mode 100644 index d99fb9df7..000000000 --- a/docs/op_mapmaking.inc +++ /dev/null @@ -1,28 +0,0 @@ -.. _opmapmaking: - -Map Making Tools ------------------------------- - -CMB map-making codes and algorithms have a long history going back more than 20 years. -Early work focused on finding the maximum likelihood solution to the noise-weighted -least squares expression for the pixelized map (and other parameters) given the data and -an estimate of the time domain noise. Later efforts took other approaches, such as the -destriping formalism used in Planck and agressive filtering and binning used in -some ground experiments. In terms of algorithms built in to TOAST, there are 2 primary tools. The first is a wrapper around the external libmadam destriping map-maker. The second is a set of native mapmaking tools which are already quite usable for many common cases. - -Libmadam Wrapper -~~~~~~~~~~~~~~~~~~~~ - -This operator has some basic options and can also take a dictionary of parameters to pass to the underlying Fortran code for complete control over the options. - -.. autoclass:: toast.todmap.OpMadam - :members: - - -Native Tools -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. todo:: Document these more fully once the communication performance bottleneck is fixed. - -.. autoclass:: toast.todmap.OpMapMaker - :members: diff --git a/docs/op_pointing.inc b/docs/op_pointing.inc deleted file mode 100644 index fb8fb42d0..000000000 --- a/docs/op_pointing.inc +++ /dev/null @@ -1,21 +0,0 @@ -.. _pointing: - -Pointing Matrices ----------------------------- - -A "pointing matrix" in TOAST terms is the sparse matrix that describes how sky signal is projected to the timestream. In particular, the model we use is - -.. math:: - - d_t = \mathcal{A}_{tp} s_p + n_t - -where we write :math:`s_p` as a column vector having a number of rows given by the number of pixels in the sky. So the :math:`\mathcal{A}_{tp}` matrix has a number of rows given by the number of time samples and a column for every sky pixel. In practice, the pointing matrix is sparse, and we only store the nonzero elements in each row. Also, our sky model often includes multiple terms (e.g. I, Q, and U). This is equivalent to having a set of values at each sky pixel. In TOAST we represent the pointing matrix as a vector of pixel indices (one for each sample) and a 2D array of "weights" whose values are the nonzero values of the matrix for each sample. TOAST includes a generic HEALPix operator to generate a pointing matrix. - - -Generic HEALPix Representation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: toast.todmap.OpPointingHpix - :members: - -Each experiment might create other specialized pointing matrices used in solving for instrument-specific signals. diff --git a/docs/op_processing.inc b/docs/op_processing.inc deleted file mode 100644 index 1a53026c6..000000000 --- a/docs/op_processing.inc +++ /dev/null @@ -1,41 +0,0 @@ -.. _opprocessing: - -Timestream Processing ------------------------------- - -Many timestream manipulations done prior to map-making are very specific to the instrument. However there are a few operations that are generically useful. - -Filtering -~~~~~~~~~~~~~~~~~~~~ - -This operator is used to build a template in azimuth bins of signal that is fixed in the scanning reference frame. This template is then subtracted from the timestream. - -.. autoclass:: toast.todmap.OpGroundFilter - :members: - -This next operator fits a polynomial to each scan and subtracts it. - -.. autoclass:: toast.tod.OpPolyFilter - :members: - -Calibration -~~~~~~~~~~~~~~~~~ - -This operator applies a set of gains to the timestreams: - -.. autoclass:: toast.tod.OpApplyGain - :members: - -Utilities -~~~~~~~~~~~~~~~~~~~~~ - -These operators are used to manipulate cached data or perform other helper functions. - -.. autoclass:: toast.tod.OpFlagGaps - :members: - -.. autoclass:: toast.tod.OpFlagsApply - :members: - -.. autoclass:: toast.tod.OpMemoryCounter - :members: diff --git a/docs/op_sim_noise.inc b/docs/op_sim_noise.inc deleted file mode 100644 index fd032c5a6..000000000 --- a/docs/op_sim_noise.inc +++ /dev/null @@ -1,9 +0,0 @@ -.. _opsimnoise: - -Simulated Detector Noise ------------------------------- - -TOAST includes an operator that simulates basic detector noise (1/f spectrum plus white noise), and also supports generating correlated noise by specifying a mixing matrix to combine individual detector streams with common mode sources. - -.. autoclass:: toast.tod.OpSimNoise - :members: diff --git a/docs/op_sim_signal.inc b/docs/op_sim_signal.inc deleted file mode 100644 index e0ee230a2..000000000 --- a/docs/op_sim_signal.inc +++ /dev/null @@ -1,59 +0,0 @@ -.. _opsimsignal: - -Simulated Detector Signal ------------------------------- - -Every experiment is different, and a realistic simulation will likely require some -customized code to model the instrument. However some kinds of simulations are generic, -especially when doing trade studies in the early design phase of a project. TOAST comes -with several built-in operators for simulating detector signals. - -Sky Model -~~~~~~~~~~~~~~ - -"Sky" In this case are sources of signals coming from outside of the Earth. The most simplistic model of the sky is just an input map at the same pixelization that is used for analysis (to avoid pixelization effects). There can be one map per detector or one map for a set of detectors (for example if simulating all detectors in a band without including bandpass variability): - -.. autoclass:: toast.todmap.OpSimScan - :members: - -The cosmological and orbital dipole can be simulated with this operator: - -.. autoclass:: toast.todmap.OpSimDipole - :members: - -TOAST can also use some external packages for more complicated sky simulations. One of these is PySM, which supports generating bandpass-integrated sky maps in memory for each detector from a set of component maps. It can also do basic smoothing of the input signal: - -.. autoclass:: toast.todmap.OpSimPySM - :members: - -For studies of far side lobes and full 4Pi beams, TOAST can use the external libconviqt package to convolve beam a_lm's with a sky a_lm at every sample: - -.. autoclass:: toast.todmap.OpSimConviqt - :members: - - -Atmosphere Simulation -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Although many ground experiments have traditionally modelled atmosphere as "correlated -noise", in TOAST we take a different approach. For each observation, a realization of -the physical atmosphere slab is created and moved according to the wind speed. Every -detector sample is formed by a line of sight integral through this slab. This sort of -real-space modelling naturally leads to correlated signal in the time domain that -depends on atmospheric parameters and focalplane geometry. - -.. autoclass:: toast.todmap.OpSimAtmosphere - :members: - -Other Signals -~~~~~~~~~~~~~~~~~ - -Any systematic contaminant that is constant (for an observation) in the scanning reference frame (as opposed to sky coordinates), can be simulated as "Scan Synchronous Signal": - -.. autoclass:: toast.todmap.OpSimScanSynchronousSignal - :members: - -This next operator can be used to apply random gain errors to the timestreams: - -.. autoclass:: toast.tod.OpGainScrambler - :members: diff --git a/docs/operators.rst b/docs/operators.rst deleted file mode 100644 index a54d45f9a..000000000 --- a/docs/operators.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _operators: - -Operators -================= - -TOAST workflows ("pipelines") consist of a :class:`toast.Data` object that is passed through one or more "operators": - -.. autoclass:: toast.Operator - :members: - -There are very few restrictions on an "operator" class. It can have arbitrary -constructor arguments and must define an `exec()` method which takes a `toast.Data` -instance. TOAST ships with many built-in operators that are detailed in the rest of -this section. Operator constructors frequently require many options. Most built-in -operators have helper functions in the `toast.pipeline_tools` module to ease parsing of -these options from the command line or argparse input file. - -.. todo:: Document the pipeline_tools functions for each built-in operator. - -.. include:: op_pointing.inc - -.. include:: op_sim_signal.inc - -.. include:: op_sim_noise.inc - -.. include:: op_processing.inc - -.. include:: op_mapmaking.inc diff --git a/docs/pipe_satellite_sim.inc b/docs/pipe_satellite_sim.inc deleted file mode 100644 index f15f3778d..000000000 --- a/docs/pipe_satellite_sim.inc +++ /dev/null @@ -1,107 +0,0 @@ -.. code-block:: console - - def main(): - env = Environment.get() - log = Logger.get() - - mpiworld, procs, rank, comm = pipeline_tools.get_comm() - args, comm, groupsize = parse_arguments(comm, procs) - - # Parse options - - if comm.world_rank == 0: - os.makedirs(args.outdir, exist_ok=True) - - focalplane, gain, detweights = load_focalplane(args, comm) - - data = create_observations(args, comm, focalplane, groupsize) - - pipeline_tools.expand_pointing(args, comm, data) - - signalname = None - skyname = pipeline_tools.simulate_sky_signal( - args, comm, data, [focalplane], "signal" - ) - if skyname is not None: - signalname = skyname - - skyname = pipeline_tools.apply_conviqt(args, comm, data, "signal") - if skyname is not None: - signalname = skyname - - diponame = pipeline_tools.simulate_dipole(args, comm, data, "signal") - if diponame is not None: - signalname = diponame - - # Mapmaking. - - if not args.use_madam: - if comm.world_rank == 0: - log.info("Not using Madam, will only make a binned map") - - npp, zmap = pipeline_tools.init_binner(args, comm, data, detweights) - - # Loop over Monte Carlos - - firstmc = args.MC_start - nmc = args.MC_count - - for mc in range(firstmc, firstmc + nmc): - outpath = os.path.join(args.outdir, "mc_{:03d}".format(mc)) - - pipeline_tools.simulate_noise( - args, comm, data, mc, "tot_signal", overwrite=True - ) - - # add sky signal - pipeline_tools.add_signal(args, comm, data, "tot_signal", signalname) - - if gain is not None: - op_apply_gain = OpApplyGain(gain, name="tot_signal") - op_apply_gain.exec(data) - - if mc == firstmc: - # For the first realization, optionally export the - # timestream data. If we had observation intervals defined, - # we could pass "use_interval=True" to the export operators, - # which would ensure breaks in the exported data at - # acceptable places. - pipeline_tools.output_tidas(args, comm, data, "tot_signal") - pipeline_tools.output_spt3g(args, comm, data, "tot_signal") - - pipeline_tools.apply_binner( - args, comm, data, npp, zmap, detweights, outpath, "tot_signal" - ) - - else: - - # Initialize madam parameters - - madampars = pipeline_tools.setup_madam(args) - - # Loop over Monte Carlos - - firstmc = args.MC_start - nmc = args.MC_count - - for mc in range(firstmc, firstmc + nmc): - # create output directory for this realization - outpath = os.path.join(args.outdir, "mc_{:03d}".format(mc)) - - pipeline_tools.simulate_noise( - args, comm, data, mc, "tot_signal", overwrite=True - ) - - # add sky signal - pipeline_tools.add_signal(args, comm, data, "tot_signal", signalname) - - if gain is not None: - op_apply_gain = OpApplyGain(gain, name="tot_signal") - op_apply_gain.exec(data) - - pipeline_tools.apply_madam( - args, comm, data, madampars, outpath, detweights, "tot_signal" - ) - - if comm.comm_world is not None: - comm.comm_world.barrier() diff --git a/docs/pipelines.rst b/docs/pipelines.rst deleted file mode 100644 index 33f9238cb..000000000 --- a/docs/pipelines.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. _pipelines: - -Pipelines -================================= - -TOAST pipelines are a top-level python script which instantiates a `toast.Data` object -as well as one or more `toast.Operator` classes which are applied to the data. - -Each operator might take many arguments in its constructor. There are helper functions -in `toast.pipeline_tools` that can be used to create some built-in operators in a -pipeline script. Currently these helper functions add arguments to an `argparse` -namespace for control at the command line. In the future, we intend to support loading -operator configuration from other config file formats. - -The details of how the global data object is created will depend on a particular project -and likely use classes specific to that experiment. Here we look at several examples -using built-in classes. - - -Example: Simple Satellite Simulation ------------------------------------------ - -TOAST includes several "generic" pipelines that simulate some fake data and then run some operators on that data. One of these is installed as `toast_satellite_sim.py`. There is some "set up" in the top of the script, but if we remove the timing code then the `main()` looks like this: - -.. include:: pipe_satellite_sim.inc diff --git a/docs/rtd_requirements.txt b/docs/rtd_requirements.txt deleted file mode 100644 index 3886a9943..000000000 --- a/docs/rtd_requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake>=3.12.0 -numpy -scipy -healpy -astropy -h5py -ephem diff --git a/docs/tutorial.rst b/docs/tutorial.rst deleted file mode 100644 index 042fc0396..000000000 --- a/docs/tutorial.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _tutorial: - -Tutorial -================================= - -The TOAST tutorial is based on a series of notebooks that were presented in past -workshops. You can find them inside the ``tutorial`` directory in the `top level of the -source tree `_. These notebooks -are designed to be run interactively from a laptop or workstation. To avoid adding -binary objects to the git repository, these notebooks do not have any outputs saved. -You can either run them to view the output or you can browse a copy of the `generated -output here `_. diff --git a/docs/utils.rst b/docs/utils.rst deleted file mode 100644 index f08d11c69..000000000 --- a/docs/utils.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _utils: - -Utilities -================================= - -TOAST contains a variety of utilities for controlling the runtime environment, logging, timing, streamed random number generation, quaternion operations, FFTs, and special function evaluation. In some cases these utilities provide a common interface to compile-time selected vendor math libraries. - -.. include:: utils_env.inc - -.. include:: utils_timing.inc - -.. include:: utils_rng.inc - -.. include:: utils_vmath.inc diff --git a/docs/utils_env.inc b/docs/utils_env.inc deleted file mode 100644 index 6edf3f5cf..000000000 --- a/docs/utils_env.inc +++ /dev/null @@ -1,18 +0,0 @@ -.. _utilsenv: - -Environment Control --------------------------------- - -The run-time behavior of the TOAST package can be controlled by the manipulation of several environment variables. The current configuration can also be queried. - -.. autoclass:: toast.utils.Environment - :members: - - -Logging --------------------------------- - -Although python provides logging facilities, those are not accessible to C++. The logging class provided in TOAST is usable from within the compiled libtoast code and also from python, and uses logging level independent from the builtin python logger. - -.. autoclass:: toast.utils.Logger - :members: diff --git a/docs/utils_rng.inc b/docs/utils_rng.inc deleted file mode 100644 index 36d55910b..000000000 --- a/docs/utils_rng.inc +++ /dev/null @@ -1,12 +0,0 @@ -.. _utilsrng: - -Random Number Generation ------------------------------------ - -The following functions define wrappers around an internally-built version of the Random123 package for streamed random number generation. This generator is fast and can return reproducible values from any location in the stream specified by the input key and counter values. - -.. autofunction:: toast.rng.random - -If generating samples from multiple different streams you can use this function: - -.. autofunction:: toast.rng.random_multi diff --git a/docs/utils_timing.inc b/docs/utils_timing.inc deleted file mode 100644 index b9f98153a..000000000 --- a/docs/utils_timing.inc +++ /dev/null @@ -1,24 +0,0 @@ -.. _utilstiming: - -Timing ------------------------------------ - -TOAST includes some utilities for setting arbitrary timers on individual processes and also gathering timer data across MPI processes. A basic manual timer is implemented in the ``Timer`` class: - -.. autoclass:: toast.timing.Timer - :members: - -A single ``Timer`` instance is only valid until it goes out of scope. To start and stop a global timer that is accessible anywhere in the code, use the ``get()`` method of the ``GlobalTimers`` singleton to get a handle to the single instance and then use the class methods to start and stop a named timer: - -.. autoclass:: toast.timing.GlobalTimers - :members: - -The ``GlobalTimers`` object can be used to automatically time all calls to a particular function by using the ``@function_timer`` decorator when defining the function. - -To gather timing statistics across all processes you can use this function: - -.. autofunction:: toast.timing.gather_timers - -And the resulting information can be written on the root process with: - -.. autofunction:: toast.timing.dump diff --git a/docs/utils_vmath.inc b/docs/utils_vmath.inc deleted file mode 100644 index b538d27f8..000000000 --- a/docs/utils_vmath.inc +++ /dev/null @@ -1,24 +0,0 @@ -.. _utilsvmath: - -Vector Math Operations ------------------------------------ - -The following functions are just simple wrappers vendor math libraries or the default -libm. They exist mainly just to provide a common interface to architecture-specific -math libraries. - -.. autofunction:: toast.utils.vsin - -.. autofunction:: toast.utils.vcos - -.. autofunction:: toast.utils.vsincos - -.. autofunction:: toast.utils.vatan2 - -.. autofunction:: toast.utils.vsqrt - -.. autofunction:: toast.utils.vrsqrt - -.. autofunction:: toast.utils.vexp - -.. autofunction:: toast.utils.vlog diff --git a/etc/flac_test/Makefile b/etc/flac_test/Makefile new file mode 100644 index 000000000..6f7a5b28c --- /dev/null +++ b/etc/flac_test/Makefile @@ -0,0 +1,13 @@ +# Copyright (c) 2015-2023 by the parties listed in the AUTHORS file. +# All rights reserved. Use of this source code is governed by +# a BSD-style license that can be found in the LICENSE file. + +CXX := g++ +CXXFLAGS := -O0 -g -fPIC -I/home/kisner/software/conda/envs/toast/include + +flac_test : main.cpp + $(CXX) $(CXXFLAGS) -o flac_test main.cpp -lFLAC -lm + +clean : + rm -f flac_test *.o + diff --git a/etc/flac_test/main.cpp b/etc/flac_test/main.cpp new file mode 100644 index 000000000..e33af33a4 --- /dev/null +++ b/etc/flac_test/main.cpp @@ -0,0 +1,345 @@ +// Copyright (c) 2023-2023 by the parties listed in the AUTHORS file. +// All rights reserved. Use of this source code is governed by +// a BSD-style license that can be found in the LICENSE file. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +void fake_data(std::vector & data) { + std::random_device dev; + std::mt19937 rng(dev()); + + int32_t max = std::numeric_limits::max() / 2; + int32_t min = -max; + std::uniform_int_distribution dist(min, max); + + for (auto & p : data) { + p = dist(rng); + } + return; +} + + + +typedef struct { + std::vector * compressed; +} enc_write_callback_data; + + +FLAC__StreamEncoderWriteStatus enc_write_callback( + const FLAC__StreamEncoder *encoder, + const FLAC__byte buffer[], + size_t bytes, + uint32_t samples, + uint32_t current_frame, + void *client_data +) { + enc_write_callback_data * data = (enc_write_callback_data *)client_data; + std::cerr << "Encode frame " << current_frame << " got " << bytes << " bytes for " << samples << " samples" << std::endl; + data->compressed->insert( + data->compressed->end(), + buffer, + buffer + bytes + ); + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + + +void encode_flac( + std::vector const & data, + std::vector & bytes, + std::vector & offsets, + uint32_t level, + int64_t stride +) { + // If stride is specified, check consistency. + int64_t n_sub; + if (stride > 0) { + if (data.size() % stride != 0) { + std::cerr << "Stride " << stride << " does not evenly divide into " << data.size() << std::endl; + return; + } + n_sub = (int64_t)(data.size() / stride); + } else { + n_sub = 1; + stride = data.size(); + } + offsets.resize(n_sub); + bytes.clear(); + + enc_write_callback_data write_callback_data; + write_callback_data.compressed = &bytes; + + // settings + + bool success; + + FLAC__StreamEncoderInitStatus status; + + FLAC__StreamEncoder * encoder; + + for (int64_t sub = 0; sub < n_sub; ++sub) { + offsets[sub] = bytes.size(); + + std::cerr << "Encoding " << stride << " samples at byte offset " << offsets[sub] << " starting at data element " << (sub * stride) << std::endl; + + encoder = FLAC__stream_encoder_new(); + + success = FLAC__stream_encoder_set_compression_level(encoder, level); + if (! success) { + std::cerr << "Failed to set compression level" << std::endl; + return; + } + + success = FLAC__stream_encoder_set_blocksize(encoder, 0); + if (! success) { + std::cerr << "Failed to set blocksize" << std::endl; + return; + } + + success = FLAC__stream_encoder_set_channels(encoder, 1); + if (! success) { + std::cerr << "Failed to set channels" << std::endl; + return; + } + + success = FLAC__stream_encoder_set_bits_per_sample(encoder, 32); + if (! success) { + std::cerr << "Failed to set bits per sample" << std::endl; + return; + } + + status = FLAC__stream_encoder_init_stream( + encoder, + enc_write_callback, + NULL, + NULL, + NULL, + (void *)&write_callback_data + ); + if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + std::cerr << "Failed to init encoder, status = " << status << std::endl; + return; + } + + success = FLAC__stream_encoder_process_interleaved( + encoder, + &(data[sub * stride]), + stride + ); + if (! success) { + std::cerr << " Failed" << std::endl; + FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(encoder); + std::cerr << " state was " << state << std::endl; + break; + } + success = FLAC__stream_encoder_finish(encoder); + if (! success) { + std::cerr << "Failed encode finish" << std::endl; + } + + FLAC__stream_encoder_delete(encoder); + } + + return; +} + +// ------------- decoding ------------------- + +typedef struct { + std::vector const * input; + size_t in_offset; + size_t in_end; + std::vector * output; +} dec_callback_data; + + +FLAC__StreamDecoderReadStatus dec_read_callback( + const FLAC__StreamDecoder * decoder, + FLAC__byte buffer[], + size_t * bytes, + void * client_data +) { + dec_callback_data * callback_data = (dec_callback_data*)client_data; + std::vector const * input = callback_data->input; + size_t offset = callback_data->in_offset; + size_t remaining = callback_data->in_end - offset; + std::cerr << "Decode read: " << remaining << " bytes remaining" << std::endl; + + // The bytes requested by the decoder + size_t n_buffer = (*bytes); + + if (remaining == 0) { + // No data left + (*bytes) = 0; + std::cerr << "Decode read: 0 bytes remaining, END_OF_STREAM" << std::endl; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } else { + // We have some data left + if (n_buffer == 0) { + // ... but there is no place to put it! + std::cerr << "Decode read: 0 bytes in buffer, ABORT" << std::endl; + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } else { + if (remaining > n_buffer) { + // Only copy in what there is space for + std::cerr << "Decode read: putting " << n_buffer << " bytes at offset " << offset << " into buffer, CONTINUE" << std::endl; + for (size_t i = 0; i < n_buffer; ++i) { + buffer[i] = (*input)[offset + i]; + } + callback_data->in_offset += n_buffer; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } else { + // Copy in the rest of the buffer and reset the number of bytes + std::cerr << "Decode read: putting remainder of " << remaining << " bytes at offset " << offset << " into buffer, CONTINUE" << std::endl; + for (size_t i = 0; i < remaining; ++i) { + buffer[i] = (*input)[offset + i]; + } + callback_data->in_offset += remaining; + (*bytes) = remaining; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + } + } + // Should never get here... + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +} + + +FLAC__StreamDecoderWriteStatus dec_write_callback( + const FLAC__StreamDecoder * decoder, + const FLAC__Frame * frame, + const FLAC__int32 * const buffer[], + void * client_data +) { + dec_callback_data * data = (dec_callback_data *)client_data; + size_t offset = data->output->size(); + uint32_t blocksize = frame->header.blocksize; + data->output->resize(offset + blocksize); + for (size_t i = 0; i < blocksize; ++i) { + (*data->output)[offset + i] = buffer[0][i]; + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + + +void dec_err_callback( + const FLAC__StreamDecoder * decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data +) { + dec_callback_data * data = (dec_callback_data *)client_data; + + return; +} + + +void decode_flac( + std::vector const & bytes, + std::vector const & offsets, + std::vector & data +) { + dec_callback_data callback_data; + callback_data.input = &bytes; + callback_data.output = &data; + + FLAC__StreamDecoder * decoder; + + + bool success; + + FLAC__StreamDecoderInitStatus status; + + + size_t n_sub = offsets.size(); + + for (size_t sub = 0; sub < n_sub; ++sub) { + callback_data.in_offset = offsets[sub]; + if (sub == n_sub - 1) { + callback_data.in_end = bytes.size(); + } else { + callback_data.in_end = offsets[sub + 1]; + } + std::cerr << "Decoding chunk " << sub << " at byte offset " << callback_data.in_offset << " with " << (callback_data.in_end - callback_data.in_offset) << " bytes" << std::endl; + + decoder = FLAC__stream_decoder_new(); + + status = FLAC__stream_decoder_init_stream( + decoder, + dec_read_callback, + NULL, + NULL, + NULL, + NULL, + dec_write_callback, + NULL, + dec_err_callback, + (void *)&callback_data + ); + if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + std::cerr << "Failed to init decoder, status = " << status << std::endl; + return; + } + + success = FLAC__stream_decoder_process_until_end_of_stream(decoder); + if (! success) { + std::cerr << " Failed" << std::endl; + break; + } + + success = FLAC__stream_decoder_finish(decoder); + if (! success) { + std::cerr << "Failed decode finish" << std::endl; + } + + FLAC__stream_decoder_delete(decoder); + } + + + return; +} + + +int main(int argc, char * argv[]) { + + int64_t n_det = 10; + int64_t n_samp = 100000; + + std::vector data(n_samp * n_det); + std::vector compressed; + std::vector offsets; + std::vector output; + + fake_data(data); + + encode_flac(data, compressed, offsets, 5, n_samp); + + std::cout << "Input was " << n_samp * n_det * 8 << " bytes, compress to " << compressed.size() << " bytes" << std::endl; + + decode_flac(compressed, offsets, output); + + for (int64_t i = 0; i < n_det; ++i) { + for (int64_t j = 0; j < n_samp; ++j) { + if (data[i * n_samp + j] != output[i * n_samp + j]) { + std::cerr << "Det " << i << ", sample " << j << ": " << output[i * n_samp + j] << " != " << data[i * n_samp + j] << std::endl; + } + } + } + + + return 0; +} + diff --git a/etc/map_comm/run_knl.slurm b/etc/map_comm/run_knl.slurm new file mode 100644 index 000000000..abad0c9ed --- /dev/null +++ b/etc/map_comm/run_knl.slurm @@ -0,0 +1,63 @@ +#!/bin/bash -l + +#SBATCH --partition=debug +#SBATCH --constraint=knl,quad,cache +#SBATCH --account=mp107 +#SBATCH --nodes=1 +#SBATCH --core-spec=4 +#SBATCH --time=00:30:00 +#SBATCH --job-name=mapcomm + +set -e + +echo "Starting batch script at $(date)" + +# Set TMPDIR to be on the ramdisk +export TMPDIR=/dev/shm + +# Numba threading may conflict with our own. Disable it. +export NUMBA_NUM_THREADS=1 + +# nodes used by this job +NODES=${SLURM_JOB_NUM_NODES} + +# set procs and threads +NODE_PROC=16 +PROC_THREADS=4 +PROC_DEPTH=$(( 256 / NODE_PROC )) + +# total number of processes on all nodes +NPROC=$(( NODES * NODE_PROC )) + +echo "Using ${NODES} node(s), which have 256 thread slots each." +echo "Starting ${NODE_PROC} process(es) per node (${NPROC} total), each with ${PROC_THREADS} OpenMP threads." + +export OMP_NUM_THREADS=${PROC_THREADS} +export OMP_PROC_BIND=spread +export OMP_PLACES=threads + +# The launching command and options +launch_str="srun" +if [ "x-n" != "x" ]; then + launch_str="${launch_str} -n ${NPROC}" +fi +if [ "x-N" != "x" ]; then + launch_str="${launch_str} -N ${NODES}" +fi +if [ "x-c" != "x" ]; then + launch_str="${launch_str} -c ${PROC_DEPTH}" +fi +launch_str="${launch_str} --cpu_bind=cores" + +# Run the pipeline script + +export TOAST_FUNCTIME=1 + +for nside in 512 1024 2048 4096; do + com="${launch_str} python toast_map_comm.py --nside ${nside}" + echo ${com} + echo "Launching pipeline at $(date)" + eval ${com} > log 2>&1 +done + +echo "Ending batch script at $(date)" diff --git a/etc/map_comm/toast_map_comm.py b/etc/map_comm/toast_map_comm.py new file mode 100644 index 000000000..572f5141d --- /dev/null +++ b/etc/map_comm/toast_map_comm.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020-2020 by the parties listed in the AUTHORS file. +# All rights reserved. Use of this source code is governed by +# a BSD-style license that can be found in the LICENSE file. + +""" +Distributed map communication tests. +""" + +import os +import sys + +import argparse + +import traceback + +import numpy as np + +import healpy as hp + +import toast + +from toast.mpi import get_world, Comm + +from toast.dist import Data + +from toast.utils import Logger, Environment + +from toast.timing import Timer, GlobalTimers, gather_timers + +from toast.timing import dump as dump_timing + +from toast import dump_config, parse_config, create + +from toast.pixels import PixelDistribution, PixelData + +from toast.pixels_io import write_healpix_fits + +from toast import future_ops as ops + +from toast.future_ops.sim_focalplane import fake_hexagon_focalplane + +from toast.instrument import Telescope + + +def main(): + env = Environment.get() + log = Logger.get() + + gt = GlobalTimers.get() + gt.start("toast_map_comm (total)") + + mpiworld, procs, rank = get_world() + + # Argument parsing + parser = argparse.ArgumentParser( + description="TOAST distributed map communication tests." + ) + + parser.add_argument( + "--nside", required=False, type=int, default=256, help="Map NSIDE" + ) + + parser.add_argument( + "--nside_submap", required=False, type=int, default=16, help="Submap NSIDE" + ) + + parser.add_argument( + "--comm_mb", + required=False, + type=int, + default=10, + help="Size in MB of allreduce buffer", + ) + + args = parser.parse_args() + + # Test different types of submap distribution. + + n_pix = 12 * args.nside ** 2 + n_pix_submap = 12 * args.nside_submap ** 2 + n_sub = n_pix // n_pix_submap + + # Tuples are: + # 1. Fraction of total submaps with full overlap + # 2. Fraction of total submaps held empty on all procs + # 3. Fraction of *remaining* submaps to randomly assign + + fractions = [ + #(0.00, 0.0, 0.25), + (0.00, 0.0, 0.50), + (0.00, 0.0, 0.75), + #(0.25, 0.0, 0.00), + #(0.25, 0.0, 0.25), + (0.25, 0.0, 0.50), + #(0.50, 0.0, 0.00), + (0.50, 0.0, 0.25), + #(0.50, 0.0, 0.50), + #(0.75, 0.0, 0.00), + (0.75, 0.0, 0.25), + #(0.75, 0.0, 0.50), + (1.00, 0.0, 0.00), + ] + + timing_file_root = "mapcomm_nproc-{:04d}_nside-{:04d}_nsub-{:03d}".format( + procs, args.nside, args.nside_submap + ) + timing_file = "{}.csv".format(timing_file_root) + + if os.path.isfile(timing_file): + if rank == 0: + print( + "Skipping completed job (n_proc = {}, nside = {}, nsub = {})".format( + procs, args.nside, args.nside_submap + ) + ) + return + + for full, empty, fill in fractions: + perc_full = int(100 * full) + perc_empty = int(100 * empty) + perc_fill = int(100 * fill) + + n_full = int(full * n_sub) + n_empty = int((n_sub - n_full) * empty) + n_fill = int((n_sub - n_full - n_empty) * fill) + fill_start = n_full + n_empty + local_submaps = [x for x in range(n_full)] + # print("loc = {}, fill_start = {}".format(local_submaps, fill_start)) + if n_fill > 0: + rem = n_sub - n_full - n_empty + flist = [x + fill_start for x in range(rem)] + n_remove = rem - n_fill + for nr in range(n_remove): + select = np.random.randint(0, high=len(flist), size=1, dtype=np.int32) + del flist[select[0]] + local_submaps.extend(flist) + dist = PixelDistribution( + n_pix=n_pix, n_submap=n_sub, local_submaps=local_submaps, comm=mpiworld + ) + # print("rank {} submaps: {}".format(rank, dist.local_submaps)) + + # Output file root + outroot = "mapcomm_nproc-{:04d}_nside-{:04d}_nsub-{:03d}_full-{:03d}_empty-{:03d}_fill-{:03d}".format( + procs, args.nside, args.nside_submap, perc_full, perc_empty, perc_fill + ) + + # Coverage map + cover = PixelData(dist, np.int32, n_value=1) + + # Set local submaps + cover.raw[:] = 1 + + # Write coverage info + if rank == 0: + fcover = cover.storage_class(dist.n_pix) + fview = fcover.array() + for lc, sm in enumerate(dist.local_submaps): + offset = sm * dist.n_pix_submap + loffset = lc * dist.n_pix_submap + fview[offset : offset + dist.n_pix_submap] = cover.raw[ + loffset : loffset + dist.n_pix_submap + ] + outfile = "{}_cover-root.fits".format(outroot) + if os.path.isfile(outfile): + os.remove(outfile) + hp.write_map(outfile, fview, dtype=np.int32, fits_IDL=False, nest=True) + del fview + fcover.clear() + del fcover + + cover.sync_allreduce() + + outfile = "{}_cover.fits".format(outroot) + write_healpix_fits(cover, outfile, nest=True) + + cover.clear() + del cover + + # Data map for communication + pix = PixelData(dist, np.float64, n_value=3) + + # Set local submaps + pix.raw[:] = 1.0 + + # Time the different sync techniques + niter = 5 + + allreduce_seconds = None + alltoallv_seconds = None + tm = Timer() + + gtname = "SYNC_ALLREDUCE_{}_{}_{}".format(perc_full, perc_empty, perc_fill) + + if mpiworld is not None: + mpiworld.barrier() + tm.clear() + tm.start() + gt.start(gtname) + + cbytes = args.comm_mb * 1000000 + for i in range(niter): + pix.sync_allreduce(comm_bytes=cbytes) + + if mpiworld is not None: + mpiworld.barrier() + tm.stop() + gt.stop(gtname) + + allreduce_seconds = tm.seconds() / niter + msg = "{} / {} / {}: Allreduce average time = {:0.2f} seconds".format( + perc_full, perc_empty, perc_fill, allreduce_seconds + ) + if rank == 0: + print(msg) + + gtname = "SYNC_ALLTOALLV_{}_{}_{}".format(perc_full, perc_empty, perc_fill) + + if mpiworld is not None: + mpiworld.barrier() + tm.clear() + tm.start() + gt.start(gtname) + + for i in range(niter): + pix.sync_alltoallv() + + if mpiworld is not None: + mpiworld.barrier() + tm.stop() + gt.stop(gtname) + + alltoallv_seconds = tm.seconds() / niter + msg = "{} / {} / {}: Alltoallv average time = {:0.2f} seconds".format( + perc_full, perc_empty, perc_fill, alltoallv_seconds + ) + if rank == 0: + print(msg) + + pix.clear() + del pix + + gt.stop_all() + alltimers = gather_timers(comm=mpiworld) + if rank == 0: + dump_timing( + alltimers, + "mapcomm_nproc-{:04d}_nside-{:04d}_nsub-{:03d}".format( + procs, args.nside, args.nside_submap + ), + ) + + return + + +if __name__ == "__main__": + try: + main() + except Exception: + # We have an unhandled exception on at least one process. Print a stack + # trace for this process and then abort so that all processes terminate. + mpiworld, procs, rank = get_world() + if procs == 1: + raise + exc_type, exc_value, exc_traceback = sys.exc_info() + lines = traceback.format_exception(exc_type, exc_value, exc_traceback) + lines = ["Proc {}: {}".format(rank, x) for x in lines] + print("".join(lines), flush=True) + if mpiworld is not None: + mpiworld.Abort() diff --git a/etc/map_comm/toast_plot_map_comm.py b/etc/map_comm/toast_plot_map_comm.py new file mode 100755 index 000000000..8a31d2919 --- /dev/null +++ b/etc/map_comm/toast_plot_map_comm.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 + +import os +import sys +import re + +import csv + +import numpy as np + +import healpy as hp + +import matplotlib + +matplotlib.use("pdf") + +import matplotlib.pyplot as plt + + +# Load all the cases + +cases = dict() + +tmpat = re.compile(r"mapcomm_nproc-(.*)_nside-(.*)_nsub-(.*)\.csv") +mappat = re.compile( + r"mapcomm_nproc-(.*)_nside-(.*)_nsub-(.*)_full-(.*)_empty-(.*)_fill-(.*)_cover\.fits" +) +rootmappat = re.compile( + r"mapcomm_nproc-(.*)_nside-(.*)_nsub-(.*)_full-(.*)_empty-(.*)_fill-(.*)_cover-root\.fits" +) + +allreduce_pat = re.compile(r"SYNC_ALLREDUCE_(\d+)_(\d+)_(\d+)") + +alltoallv_pat = re.compile(r"SYNC_ALLTOALLV_(\d+)_(\d+)_(\d+)") + + +def case_init(tcases, nside, full, fill): + if full not in cases: + tcases[full] = dict() + if fill not in cases[full]: + tcases[full][fill] = dict() + if nside not in cases[full][fill]: + tcases[full][fill][nside] = dict() + tcases[full][fill][nside]["allreduce"] = dict() + tcases[full][fill][nside]["alltoallv"] = dict() + return + + +maxproc = 0 +maxproc_root = 0 + +for dirpath, dirnames, filenames in os.walk("."): + for file in filenames: + path = os.path.join(dirpath, file) + + mat = mappat.match(file) + if mat is not None: + print("found map file {}".format(path)) + nproc = int(mat.group(1)) + nside = int(mat.group(2)) + nsub = int(mat.group(3)) + full = int(mat.group(4)) + empty = int(mat.group(5)) + fill = int(mat.group(6)) + case_init(cases, nside, full, fill) + if nproc >= maxproc: + cases[full][fill][nside]["cover"] = path + maxproc = nproc + + mat = rootmappat.match(file) + if mat is not None: + print("found map root file {}".format(path)) + nproc = int(mat.group(1)) + nside = int(mat.group(2)) + nsub = int(mat.group(3)) + full = int(mat.group(4)) + empty = int(mat.group(5)) + fill = int(mat.group(6)) + case_init(cases, nside, full, fill) + if nproc >= maxproc_root: + cases[full][fill][nside]["rootcover"] = path + maxproc_root = nproc + + mat = tmpat.match(file) + if mat is not None: + print("found timing file {}".format(path)) + nproc = int(mat.group(1)) + nside = int(mat.group(2)) + nsub = int(mat.group(3)) + with open(path, "r") as tf: + reader = csv.reader(tf, delimiter=",") + for row in reader: + namemat = allreduce_pat.match(row[0]) + if namemat is not None: + print("Found allreduce timing {}".format(row[0])) + full = int(namemat.group(1)) + empty = int(namemat.group(2)) + fill = int(namemat.group(3)) + case_init(cases, nside, full, fill) + seconds = float(row[7]) / 5.0 + cases[full][fill][nside]["allreduce"][nproc] = seconds + namemat = alltoallv_pat.match(row[0]) + if namemat is not None: + print("Found alltoallv timing {}".format(row[0])) + full = int(namemat.group(1)) + empty = int(namemat.group(2)) + fill = int(namemat.group(3)) + case_init(cases, nside, full, fill) + seconds = float(row[7]) / 5.0 + cases[full][fill][nside]["alltoallv"][nproc] = seconds + +print(cases) + +n_case = 0 +fullvals = sorted(cases.keys()) +for full in fullvals: + fillvals = sorted(cases[full].keys()) + n_case += len(fillvals) + +fig = plt.figure(figsize=(12, 2.5 * n_case), dpi=100) + +plotrows = 0 +for x in cases.keys(): + for y in cases[x].keys(): + plotrows += 1 + +plotoff = 1 + +fullvals = sorted(cases.keys()) +for full in fullvals: + fillvals = sorted(cases[full].keys()) + for fill in fillvals: + # Find the lowest NSIDE to use for plotting, since these submap coverage plots + # will be identical for every NSIDE. + nsides = sorted(cases[full][fill].keys()) + pmax = 0 + for ns in nsides: + procs = sorted(cases[full][fill][ns]["allreduce"].keys()) + for p in procs: + if p > pmax: + pmax = p + + cover = hp.read_map(cases[full][fill][nsides[0]]["cover"]) + rootcover = hp.read_map(cases[full][fill][nsides[0]]["rootcover"]) + hp.mollview( + map=cover, + sub=(plotrows, 3, plotoff), + title="Total Submap Coverage {:d}% / {:d}%".format(full, fill), + xsize=1200, + cmap="rainbow", + min=0, + max=pmax, + margins=(0.0, 0.0, 0.0, 0.01), + ) + plotoff += 1 + hp.mollview( + map=rootcover, + sub=(plotrows, 3, plotoff), + title="Rank Zero Submaps {:d}% / {:d}%".format(full, fill), + xsize=1200, + cmap="rainbow", + min=0, + max=1, + margins=(0.0, 0.0, 0.0, 0.01), + ) + plotoff += 1 + ax = fig.add_subplot(plotrows, 3, plotoff) + for ns in nsides: + lw = 0.5 * (ns // 256) + procs = sorted(cases[full][fill][ns]["allreduce"].keys()) + xdata = np.array(procs, dtype=np.int32) + ydata = np.array([cases[full][fill][ns]["allreduce"][x] for x in procs]) + ax.plot( + xdata, + ydata, + label="allreduce N{}".format(ns), + color="r", + linewidth=lw, + marker="o", + markersize=(lw + 1), + ) + ydata = np.array([cases[full][fill][ns]["alltoallv"][x] for x in procs]) + ax.plot( + xdata, + ydata, + label="alltoallv N{}".format(ns), + color="g", + linewidth=lw, + marker="o", + markersize=(lw + 1), + ) + ax.legend(loc="upper left", fontsize=6) + + ax.set_ylabel("Seconds (Mean of {} calls)".format(5)) + ax.set_xlabel("MPI Ranks") + ax.set_ylim(0, 9.0) + plotoff += 1 + +plt.tight_layout() +# plt.subplots_adjust(top=0.9) +pfile = "mapcomm.pdf" +plt.savefig(pfile) +plt.close() diff --git a/etc/pyomptarget/Makefile b/etc/pyomptarget/Makefile new file mode 100644 index 000000000..226537378 --- /dev/null +++ b/etc/pyomptarget/Makefile @@ -0,0 +1,46 @@ + +# GCC 12.1.0 with offload support +#CXX := g++-12 +#CXXFLAGS := -O0 -g -fPIC -pthread -std=c++11 -fcf-protection=none -fno-stack-protector +#CXX_OMP_FLAGS := -fopenmp -foffload=nvptx-none='-Wa,-m,sm_80 -misa=sm_80 -fPIC -lm -latomic' + +# NVHPC +# CXX = nvc++ +# CXXFLAGS = -O0 -g -fPIC -pthread -std=c++11 +# CXX_OMP_FLAGS = -mp=gpu -Minfo=mp -gpu=cc86 + +# AMD LLVM +#CXX := amdclang++ +#CXXFLAGS := -O3 -g -fPIC -std=c++11 +#CXX_OMP_FLAGS := -fPIC -fopenmp -fopenmp-target-debug=3 -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx1030 +#CXX_LD_FLAGS := -lomp -lomptarget -lomptarget.rtl.amdgpu + +# Stock LLVM +CXX := clang++ +CXXFLAGS := -O3 -g -fPIC -std=c++11 +CXX_OMP_FLAGS := -fPIC -fopenmp -fopenmp-targets=nvptx64 -fopenmp-target-debug=3 +CXX_LD_FLAGS := -lomp -lomptarget -lomptarget.rtl.cuda + +pybind := ../../src/toast/pybind11 +modext := $(shell python3-config --extension-suffix) +pyincl := $(shell python3-config --includes) + + +all : device_info test pyomptarget$(modext) + + +pyomptarget$(modext) : module.o + $(CXX) -shared $(CXX_OMP_FLAGS) -o pyomptarget$(modext) module.o $(CXX_LD_FLAGS) + +module.o : module.cpp + $(CXX) $(CXXFLAGS) $(CXX_OMP_FLAGS) -I. -I$(pybind)/include $(pyincl) -c -o module.o module.cpp + +device_info : device_info.cpp + $(CXX) $(CXXFLAGS) $(CXX_OMP_FLAGS) -o device_info device_info.cpp $(CXX_LD_FLAGS) + +test : test.cpp + $(CXX) $(CXXFLAGS) $(CXX_OMP_FLAGS) -o test test.cpp $(CXX_LD_FLAGS) + +clean : + rm -f *.so *.o device_info test + diff --git a/etc/pyomptarget/device_info.cpp b/etc/pyomptarget/device_info.cpp new file mode 100644 index 000000000..a8d57d1f2 --- /dev/null +++ b/etc/pyomptarget/device_info.cpp @@ -0,0 +1,17 @@ + +#include +//#include "omptarget.h" +#include + +int main(int argc, char **argv) { + int ndev = omp_get_num_devices(); + std::cout << "OMP found " << ndev << " available target offload devices" << std::endl; + int target = ndev - 1; + int host = omp_get_initial_device(); + int defdev = omp_get_default_device(); + std::cout << "OMP initial host device = " << host << std::endl; + std::cout << "OMP target device = " << target << std::endl; + std::cout << "OMP default device = " << defdev << std::endl; + return 0; +} + diff --git a/etc/pyomptarget/module.cpp b/etc/pyomptarget/module.cpp new file mode 100644 index 000000000..4c9f39e1b --- /dev/null +++ b/etc/pyomptarget/module.cpp @@ -0,0 +1,787 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace py = pybind11; + +using size_container = py::detail::any_container ; + +// 2/PI +#define TWOINVPI 0.63661977236758134308 + +// 2/3 +#define TWOTHIRDS 0.66666666666666666667 + +// Helper table initialization +void hpix_init_utab(uint64_t * utab) { + for (uint64_t m = 0; m < 256; ++m) { + utab[m] = (m & 0x1) | ((m & 0x2) << 1) | ((m & 0x4) << 2) | + ((m & 0x8) << 3) | ((m & 0x10) << 4) | ((m & 0x20) << 5) | + ((m & 0x40) << 6) | ((m & 0x80) << 7); + } + return; +} + +// Device code +#pragma omp declare target + +struct Interval { + double start; + double stop; + int64_t first; + int64_t last; +}; + +void qa_mult(double const * p, double const * q, double * r) { + r[0] = p[0] * q[3] + p[1] * q[2] - + p[2] * q[1] + p[3] * q[0]; + r[1] = -p[0] * q[2] + p[1] * q[3] + + p[2] * q[0] + p[3] * q[1]; + r[2] = p[0] * q[1] - p[1] * q[0] + + p[2] * q[3] + p[3] * q[2]; + r[3] = -p[0] * q[0] - p[1] * q[1] - + p[2] * q[2] + p[3] * q[3]; + return; +} + +void qa_rotate(double const * q_in, double const * v_in, double * v_out) { + // The input quaternion has already been normalized on the host. + + double xw = q_in[3] * q_in[0]; + double yw = q_in[3] * q_in[1]; + double zw = q_in[3] * q_in[2]; + double x2 = -q_in[0] * q_in[0]; + double xy = q_in[0] * q_in[1]; + double xz = q_in[0] * q_in[2]; + double y2 = -q_in[1] * q_in[1]; + double yz = q_in[1] * q_in[2]; + double z2 = -q_in[2] * q_in[2]; + + v_out[0] = 2 * ((y2 + z2) * v_in[0] + (xy - zw) * v_in[1] + + (yw + xz) * v_in[2]) + v_in[0]; + + v_out[1] = 2 * ((zw + xy) * v_in[0] + (x2 + z2) * v_in[1] + + (yz - xw) * v_in[2]) + v_in[1]; + + v_out[2] = 2 * ((xz - yw) * v_in[0] + (xw + yz) * v_in[1] + + (x2 + y2) * v_in[2]) + v_in[2]; + + return; +} + +void pointing_detector_inner( + int32_t const * q_index, + uint8_t const * flags, + double const * boresight, + double const * fp, + double * quats, + int64_t isamp, + int64_t n_samp, + int64_t idet +) { + int32_t qidx = q_index[idet]; + double temp_bore[4]; + uint8_t check = flags[isamp] & 255; + if (check == 0) { + temp_bore[0] = boresight[4 * isamp]; + temp_bore[1] = boresight[4 * isamp + 1]; + temp_bore[2] = boresight[4 * isamp + 2]; + temp_bore[3] = boresight[4 * isamp + 3]; + } else { + temp_bore[0] = 0.0; + temp_bore[1] = 0.0; + temp_bore[2] = 0.0; + temp_bore[3] = 1.0; + } + qa_mult( + temp_bore, + &(fp[4 * idet]), + &(quats[(qidx * 4 * n_samp) + 4 * isamp]) + ); + return; +} + +uint64_t hpix_xy2pix(uint64_t * utab, uint64_t x, uint64_t y) { + return utab[x & 0xff] | (utab[(x >> 8) & 0xff] << 16) | + (utab[(x >> 16) & 0xff] << 32) | + (utab[(x >> 24) & 0xff] << 48) | + (utab[y & 0xff] << 1) | (utab[(y >> 8) & 0xff] << 17) | + (utab[(y >> 16) & 0xff] << 33) | + (utab[(y >> 24) & 0xff] << 49); +} + +void hpix_vec2zphi(double const * vec, + double * phi, int * region, double * z, + double * rtz) { + // region encodes BOTH the sign of Z and whether its + // absolute value is greater than 2/3. + (*z) = vec[2]; + double za = fabs(*z); + int itemp = ((*z) > 0.0) ? 1 : -1; + (*region) = (za <= TWOTHIRDS) ? itemp : itemp + itemp; + (*rtz) = sqrt(3.0 * (1.0 - za)); + (*phi) = atan2(vec[1], vec[0]); + return; +} + +void hpix_zphi2nest(int64_t nside, int64_t factor, uint64_t * utab, + double phi, int region, double z, + double rtz, int64_t * pix) { + double tt = (phi >= 0.0) ? phi * TWOINVPI : phi * TWOINVPI + 4.0; + int64_t x; + int64_t y; + double temp1; + double temp2; + int64_t jp; + int64_t jm; + int64_t ifp; + int64_t ifm; + int64_t face; + int64_t ntt; + double tp; + + double dnside = static_cast (nside); + int64_t twonside = 2 * nside; + double halfnside = 0.5 * dnside; + double tqnside = 0.75 * dnside; + int64_t nsideminusone = nside - 1; + + if ((region == 1) || (region == -1)) { + temp1 = halfnside + dnside * tt; + temp2 = tqnside * z; + + jp = (int64_t)(temp1 - temp2); + jm = (int64_t)(temp1 + temp2); + + ifp = jp >> factor; + ifm = jm >> factor; + + if (ifp == ifm) { + face = (ifp == 4) ? (int64_t)4 : ifp + 4; + } else if (ifp < ifm) { + face = ifp; + } else { + face = ifm + 8; + } + + x = jm & nsideminusone; + y = nsideminusone - (jp & nsideminusone); + } else { + ntt = (int64_t)tt; + + tp = tt - (double)ntt; + + temp1 = dnside * rtz; + + jp = (int64_t)(tp * temp1); + jm = (int64_t)((1.0 - tp) * temp1); + + if (jp >= nside) { + jp = nsideminusone; + } + if (jm >= nside) { + jm = nsideminusone; + } + + if (z >= 0) { + face = ntt; + x = nsideminusone - jm; + y = nsideminusone - jp; + } else { + face = ntt + 8; + x = jp; + y = jm; + } + } + + uint64_t sipf = hpix_xy2pix(utab, (uint64_t)x, (uint64_t)y); + + (*pix) = (int64_t)sipf + (face << (2 * factor)); + + return; +} + +void pixels_healpix_nest_inner( + int64_t nside, + int64_t factor, + uint64_t * utab, + int32_t const * quat_index, + int32_t const * pixel_index, + double const * quats, + uint8_t const * flags, + uint8_t * hsub, + int64_t * pixels, + int64_t n_pix_submap, + int64_t isamp, + int64_t n_samp, + int64_t idet +) { + const double zaxis[3] = {0.0, 0.0, 1.0}; + int32_t p_indx = pixel_index[idet]; + int32_t q_indx = quat_index[idet]; + double dir[3]; + double z; + double rtz; + double phi; + int region; + size_t qoff = (q_indx * 4 * n_samp) + 4 * isamp; + size_t poff = p_indx * n_samp + isamp; + int64_t sub_map; + + uint8_t check = flags[isamp] & 255; + + if (check != 0) { + pixels[poff] = -1; + } else { + qa_rotate(&(quats[qoff]), zaxis, dir); + hpix_vec2zphi(dir, &phi, ®ion, &z, &rtz); + hpix_zphi2nest(nside, factor, utab, phi, region, z, rtz, &(pixels[poff])); + sub_map = (int64_t)(pixels[poff] / n_pix_submap); + hsub[sub_map] = 1; + } + + return; +} + +#pragma omp end declare target + +template +void host_to_device( + std::unordered_map & mem, + int64_t n_elem, + T * data, + std::string const & name +) { + int target = omp_get_num_devices() - 1; + int host = omp_get_initial_device(); + + void * vdata = (void*)(&data[0]); + + size_t n_bytes = n_elem * sizeof(T); + std::cerr << name << ": Allocating " << n_bytes << " device bytes (" << n_elem << " x " << sizeof(T) << ")" << std::endl; + void * buffer = omp_target_alloc(n_bytes, target); + + std::cerr << name << ": Associating host pointer " << vdata << std::endl; + int failed = omp_target_associate_ptr(vdata, buffer, n_bytes, 0, target); + if (failed != 0) { + std::cerr << "Failed to associate dev pointer" << std::endl; + } + + failed = omp_target_memcpy(buffer, vdata, n_bytes, 0, 0, target, host); + if (failed != 0) { + std::cerr << "Failed to copy " << name << " host to device" << std::endl; + } + std::cerr << name << ": map host " << vdata << " --> " << buffer << std::endl; + mem[vdata] = buffer; + return; +} + +template +void device_to_host( + std::unordered_map & mem, + int64_t n_elem, + T * data, + std::string const & name +) { + int target = omp_get_num_devices() - 1; + int host = omp_get_initial_device(); + + void * vdata = (void*)(&data[0]); + + size_t n_bytes = n_elem * sizeof(T); + + void * buffer = mem.at(vdata); + + int failed = omp_target_memcpy(vdata, buffer, n_bytes, 0, 0, host, target); + if (failed != 0) { + std::cerr << "Failed to copy " << name << " device to host" << std::endl; + } + return; +} + + +std::string get_format(std::string const & input) { + // Machine endianness + int32_t test = 1; + bool little_endian = (*(int8_t *)&test == 1); + + std::string format = input; + + // Remove leading caret, if present. + if (format.substr(0, 1) == "^") { + format = input.substr(1, input.length() - 1); + } + + std::string fmt = format; + if (format.length() > 1) { + // The format string includes endianness information or + // is a compound type. + std::string endianness = format.substr(0, 1); + if ( + ((endianness == ">") && !little_endian) || + ((endianness == "<") && little_endian) || + (endianness == "=") + ) { + fmt = format.substr(1, format.length() - 1); + } else if ( + ((endianness == ">") && little_endian) || + ((endianness == "<") && !little_endian) + ) { + std::ostringstream o; + o << "Object has different endianness than system- cannot use"; + throw std::runtime_error(o.str().c_str()); + } + } + return fmt; +} + +template +T * extract_buffer( + py::buffer data, + char const * name, + size_t assert_dims, + std::vector & shape, + std::vector assert_shape +) { + // Get buffer info structure + auto info = data.request(); + + // Extract the format character for the target type + std::string target_format = get_format(py::format_descriptor ::format()); + + // Extract the format for the input buffer + std::string buffer_format = get_format(info.format); + + // Verify format string + if (buffer_format != target_format) { + // On 64bit linux, numpy is internally inconsistent with the + // format codes for int64_t and long long: + // https://github.com/numpy/numpy/issues/12264 + // Here we treat them as equivalent. + if (((buffer_format == "q") || (buffer_format == "l")) + && ((target_format == "q") || (target_format == "l"))) { + // What could possibly go wrong... + } else { + std::ostringstream o; + o << "Object " << name << " has format \"" << buffer_format + << "\" instead of \"" << target_format << "\""; + throw std::runtime_error(o.str().c_str()); + } + } + + // Verify itemsize + if (info.itemsize != sizeof(T)) { + std::ostringstream o; + o << "Object " << name << " has item size of " + << info.itemsize << " instead of " << sizeof(T); + throw std::runtime_error(o.str().c_str()); + } + + // Verify number of dimensions + if (info.ndim != assert_dims) { + std::ostringstream o; + o << "Object " << name << " has " << info.ndim + << " dimensions instead of " << assert_dims; + throw std::runtime_error(o.str().c_str()); + } + + // Get array dimensions + for (py::ssize_t d = 0; d < info.ndim; d++) { + shape[d] = info.shape[d]; + } + + // Check strides and verify that memory is contiguous + size_t stride = info.itemsize; + for (int d = info.ndim - 1; d >= 0; d--) { + if (info.strides[d] != stride) { + std::ostringstream o; + o << "Object " << name + << ": python buffers must be contiguous in memory."; + throw std::runtime_error(o.str().c_str()); + } + stride *= info.shape[d]; + } + + // If the user wants to verify any of the dimensions, do that + for (py::ssize_t d = 0; d < info.ndim; d++) { + if (assert_shape[d] >= 0) { + // We are checking this dimension + if (assert_shape[d] != shape[d]) { + std::ostringstream o; + o << "Object " << name << " dimension " << d + << " has length " << shape[d] + << " instead of " << assert_shape[d]; + throw std::runtime_error(o.str().c_str()); + } + } + } + + return static_cast (info.ptr); +} + + +PYBIND11_MODULE(pyomptarget, m) { + m.doc() = R"( + Compiled extension using OpenMP target offload. + + )"; + + py::class_ ( + m, "Interval", + R"( + Numpy dtype for an interval + )") + .def(py::init([]() { + return Interval(); + })) + .def_readwrite("start", &Interval::start) + .def_readwrite("stop", &Interval::stop) + .def_readwrite("first", &Interval::first) + .def_readwrite("last", &Interval::last) + .def("astuple", + [](const Interval & self) { + return py::make_tuple(self.start, self.stop, self.first, self.last); + }) + .def_static("fromtuple", [](const py::tuple & tup) { + if (py::len(tup) != 4) { + throw py::cast_error("Invalid size"); + } + return Interval{tup[0].cast (), + tup[1].cast (), + tup[2].cast (), + tup[3].cast ()}; + }); + + + PYBIND11_NUMPY_DTYPE(Interval, start, stop, first, last); + + m.def( + "stage_data", []( + py::buffer boresight, + py::buffer quats, + py::buffer intervals, + py::buffer shared_flags, + py::buffer pixels + ) { + int ndev = omp_get_num_devices(); + std::cout << "OMP found " << ndev << " available target offload devices" << std::endl; + int target = ndev - 1; + int host = omp_get_initial_device(); + int defdev = omp_get_default_device(); + std::cout << "OMP initial host device = " << host << std::endl; + std::cout << "OMP target device = " << target << std::endl; + std::cout << "OMP default device = " << defdev << std::endl; + + std::unordered_map mem; + + // This is used to return the actual shape of each buffer + std::vector temp_shape(3); + + double * raw_boresight = extract_buffer ( + boresight, "boresight", 2, temp_shape, {-1, 4} + ); + int64_t n_samp = temp_shape[0]; + + uint8_t * raw_flags = extract_buffer ( + shared_flags, "flags", 1, temp_shape, {n_samp} + ); + + double * raw_quats = extract_buffer ( + quats, "quats", 3, temp_shape, {-1, n_samp, 4} + ); + int64_t n_det = temp_shape[0]; + + int64_t * raw_pixels = extract_buffer ( + pixels, "pixels", 2, temp_shape, {n_det, n_samp} + ); + + Interval * raw_intervals = extract_buffer ( + intervals, "intervals", 1, temp_shape, {-1} + ); + int64_t n_view = temp_shape[0]; + + host_to_device(mem, 4 * n_samp, raw_boresight, "boresight"); + + host_to_device(mem, n_samp, raw_flags, "flags"); + + host_to_device(mem, n_samp * n_det, raw_pixels, "pixels"); + + host_to_device(mem, n_view, raw_intervals, "intervals"); + + host_to_device(mem, n_samp * n_det * 4, raw_quats, "quats"); + + return mem; + }); + + m.def( + "unstage_data", []( + std::unordered_map mem, + py::buffer quats, + py::buffer pixels + ) { + std::vector temp_shape(3); + double * raw_quats = extract_buffer ( + quats, "quats", 3, temp_shape, {-1, -1, 4} + ); + int64_t n_det = temp_shape[0]; + int64_t n_samp = temp_shape[1]; + int64_t * raw_pixels = extract_buffer ( + pixels, "pixels", 2, temp_shape, {n_det, n_samp} + ); + device_to_host(mem, n_samp * n_det * 4, raw_quats, "quats"); + device_to_host(mem, n_samp * n_det, raw_pixels, "pixels"); + + int target = omp_get_num_devices() - 1; + for(auto & p : mem) { + std::cerr << "Disassociate host pointer " << p.first << std::endl; + int fail = omp_target_disassociate_ptr(p.first, target); + if (fail != 0) { + std::cerr << "Failed to disassociate host pointer " << p.first << std::endl; + } + omp_target_free(p.second, target); + } + }); + + m.def( + "pointing_detector", []( + std::unordered_map mem, + py::buffer focalplane, + py::buffer boresight, + py::buffer quat_index, + py::buffer quats, + py::buffer intervals, + py::buffer shared_flags + ) { + // What if quats has more dets than we are considering in quat_index? + + // This is used to return the actual shape of each buffer + std::vector temp_shape(3); + + int32_t * raw_quat_index = extract_buffer ( + quat_index, "quat_index", 1, temp_shape, {-1} + ); + int64_t n_det = temp_shape[0]; + + double * raw_focalplane = extract_buffer ( + focalplane, "focalplane", 2, temp_shape, {n_det, 4} + ); + + double * raw_boresight = extract_buffer ( + boresight, "boresight", 2, temp_shape, {-1, 4} + ); + int64_t n_samp = temp_shape[0]; + double * dev_boresight = (double*)mem.at(raw_boresight); + + double * raw_quats = extract_buffer ( + quats, "quats", 3, temp_shape, {-1, n_samp, 4} + ); + double * dev_quats = (double*)mem.at(raw_quats); + + Interval * raw_intervals = extract_buffer ( + intervals, "intervals", 1, temp_shape, {-1} + ); + Interval * dev_intervals = (Interval*)mem.at(raw_intervals); + int64_t n_view = temp_shape[0]; + std::cerr << "interval 0 = " << raw_intervals[0].first << ", " << raw_intervals[0].last << std::endl; + + uint8_t * raw_flags = extract_buffer ( + shared_flags, "flags", 1, temp_shape, {n_samp} + ); + uint8_t * dev_flags = (uint8_t*)mem.at(raw_flags); + + int present = omp_target_is_present(raw_boresight, 0); + std::cerr << "target present boresight = " << present << std::endl; + present = omp_target_is_present(raw_quats, 0); + std::cerr << "target present quats = " << present << std::endl; + present = omp_target_is_present(raw_intervals, 0); + std::cerr << "target present intervals = " << present << std::endl; + present = omp_target_is_present(raw_flags, 0); + std::cerr << "target present flags = " << present << std::endl; + + # pragma omp target data \ + device(0) \ + map(to: \ + raw_focalplane[0:4*n_det], \ + raw_quat_index[0:n_det], \ + n_view, \ + n_det, \ + n_samp \ + ) + { + # pragma omp target teams distribute collapse(2) \ + is_device_ptr( \ + dev_boresight, \ + dev_quats, \ + dev_intervals, \ + dev_flags \ + ) + for (int64_t idet = 0; idet < n_det; idet++) { + for (int64_t iview = 0; iview < n_view; iview++) { + # pragma omp parallel for default(shared) + for ( + int64_t isamp = raw_intervals[iview].first; + isamp <= raw_intervals[iview].last; + isamp++ + ) { + // Test stack allocation with a mapped variable + //double dummy[n_det]; + + pointing_detector_inner( + raw_quat_index, + dev_flags, + dev_boresight, + raw_focalplane, + dev_quats, + isamp, + n_samp, + idet + ); + } + } + } + } + + return; + }); + + m.def( + "pixels_healpix_nest", []( + std::unordered_map mem, + py::buffer quat_index, + py::buffer quats, + py::buffer shared_flags, + py::buffer pixel_index, + py::buffer pixels, + py::buffer intervals, + py::buffer hit_submaps, + int64_t n_pix_submap, + int64_t nside + ) { + // This is used to return the actual shape of each buffer + std::vector temp_shape(3); + + int32_t * raw_quat_index = extract_buffer ( + quat_index, "quat_index", 1, temp_shape, {-1} + ); + int64_t n_det = temp_shape[0]; + + int32_t * raw_pixel_index = extract_buffer ( + pixel_index, "pixel_index", 1, temp_shape, {n_det} + ); + + int64_t * raw_pixels = extract_buffer ( + pixels, "pixels", 2, temp_shape, {-1, -1} + ); + int64_t n_samp = temp_shape[1]; + + double * raw_quats = extract_buffer ( + quats, "quats", 3, temp_shape, {-1, n_samp, 4} + ); + + Interval * raw_intervals = extract_buffer ( + intervals, "intervals", 1, temp_shape, {-1} + ); + int64_t n_view = temp_shape[0]; + + uint8_t * raw_hsub = extract_buffer ( + hit_submaps, "hit_submaps", 1, temp_shape, {-1} + ); + int64_t n_submap = temp_shape[0]; + + uint8_t * raw_flags = extract_buffer ( + shared_flags, "flags", 1, temp_shape, {n_samp} + ); + + uint64_t utab[256]; + hpix_init_utab(utab); + + int64_t factor = 0; + while (nside != (1ll << factor)) { + ++factor; + } + + double * dev_quats = (double*)mem.at(raw_quats); + + int64_t * dev_pixels = (int64_t*)mem.at(raw_pixels); + + Interval * dev_intervals = (Interval*)mem.at(raw_intervals); + + uint8_t * dev_flags = (uint8_t*)mem.at(raw_flags); + + // Make sure the lookup table exists on device + // if (mem.count(vutab) == 0) { + // host_to_device(mem, 256, utab, "hpix_utab"); + // } + // uint64_t * dev_utab = (uint64_t*)mem.at(utab); + + # pragma omp target data \ + device(0) \ + map(to: \ + utab[0:256], \ + raw_pixel_index[0:n_det], \ + raw_quat_index[0:n_det], \ + n_pix_submap, \ + nside, \ + factor, \ + n_view, \ + n_det, \ + n_samp \ + ) \ + map(tofrom: raw_hsub[0:n_submap]) + { + # pragma omp target teams distribute collapse(2) \ + is_device_ptr( \ + dev_pixels, \ + dev_quats, \ + dev_flags, \ + dev_intervals \ + ) + for (int64_t idet = 0; idet < n_det; idet++) { + for (int64_t iview = 0; iview < n_view; iview++) { + # pragma omp parallel for default(shared) + for ( + int64_t isamp = dev_intervals[iview].first; + isamp <= dev_intervals[iview].last; + isamp++ + ) { + pixels_healpix_nest_inner( + nside, + factor, + utab, + raw_quat_index, + raw_pixel_index, + dev_quats, + dev_flags, + raw_hsub, + dev_pixels, + n_pix_submap, + isamp, + n_samp, + idet + ); + } + } + } + } + + return; + }); + +} diff --git a/etc/pyomptarget/run.py b/etc/pyomptarget/run.py new file mode 100644 index 000000000..3f4bc6660 --- /dev/null +++ b/etc/pyomptarget/run.py @@ -0,0 +1,110 @@ + +import os +import sys +import time + +sys.path.append(os.getcwd()) +import pyomptarget + +# Import this **AFTER** the custom module above, since both will +# dlopen libgomp. +import numpy as np + + +def build_interval_dtype(): + dtdbl = np.dtype("double") + dtll = np.dtype("longlong") + fmts = [dtdbl.char, dtdbl.char, dtll.char, dtll.char] + offs = [ + 0, + dtdbl.alignment, + 2 * dtdbl.alignment, + 2 * dtdbl.alignment + dtll.alignment, + ] + return np.dtype( + { + "names": ["start", "stop", "first", "last"], + "formats": fmts, + "offsets": offs, + } + ) + + +def main(): + interval_dtype = build_interval_dtype() + ndet = 2 + nsamp = 1000000 + + focalplane = np.tile( + np.array( + [0.0, 0.0, 0.0, 1.0], + dtype=np.float64, + ), + ndet, + ).reshape((-1, 4)) + + boresight = np.tile( + np.array( + [0.0, 0.0, 0.0, 1.0], + dtype=np.float64, + ), + nsamp, + ).reshape((-1, 4)) + + quat_index = np.arange(ndet, dtype=np.int32) + pixel_index = np.arange(ndet, dtype=np.int32) + + shared_flags = np.zeros(nsamp, dtype=np.uint8) + + nview = 1 + print(interval_dtype) + intervals = np.zeros(nview, dtype=interval_dtype).view(np.recarray) + intervals[0].first = 0 + intervals[0].last = nsamp - 1 + intervals[0].start = -1.0 + intervals[0].stop = -1.0 + + quats = np.zeros((ndet, nsamp, 4), dtype=np.float64) + pixels = np.zeros((ndet, nsamp), dtype=np.int64) + + mem = pyomptarget.stage_data(boresight, quats, intervals, shared_flags, pixels) + + # time.sleep(5) + + pyomptarget.pointing_detector( + mem, + focalplane, + boresight, + quat_index, + quats, + intervals, + shared_flags, + ) + + nside = 1024 + nside_submap = 16 + n_pix_submap = 12 * nside_submap**2 + n_submap = (nside // nside_submap) ** 2 + hit_submaps = np.zeros(n_submap, dtype=np.uint8) + + pyomptarget.pixels_healpix_nest( + mem, + quat_index, + quats, + shared_flags, + pixel_index, + pixels, + intervals, + hit_submaps, + n_pix_submap, + nside, + ) + + pyomptarget.unstage_data(mem, quats, pixels) + + print(quats) + print(pixels) + + +if __name__ == "__main__": + main() diff --git a/etc/pyomptarget/run_rocm.sh b/etc/pyomptarget/run_rocm.sh new file mode 100755 index 000000000..7bb4a5259 --- /dev/null +++ b/etc/pyomptarget/run_rocm.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +export OMP_TARGET_OFFLOAD=MANDATORY +export OMP_DISPLAY_ENV=verbose + +#export LIBOMPTARGET_INFO=$((0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20)) +export LIBOMPTARGET_INFO=-1 +export LIBOMPTARGET_DEVICE_RTL_DEBUG=3 + +#export HSA_IGNORE_SRAMECC_MISREPORT=1 + +eval "$@" + +# OMP_NUM_THREADS=4 OMP_TARGET_OFFLOAD=MANDATORY OMP_DISPLAY_ENV=verbose LIBOMPTARGET_INFO=-1 LIBOMPTARGET_DEVICE_RTL_DEBUG=3 TOAST_LOGLEVEL=VERBOSE TOAST_GPU_OPENMP=1 toast_mini --node_mem_gb 7 2>&1 | tee log \ No newline at end of file diff --git a/etc/pyomptarget/test.cpp b/etc/pyomptarget/test.cpp new file mode 100644 index 000000000..7f214f72e --- /dev/null +++ b/etc/pyomptarget/test.cpp @@ -0,0 +1,11 @@ + +#include +#include + +int main() { + double s; +#pragma omp target teams distribute parallel for reduction(+:s) map(tofrom:s) + for (int idx = 0; idx < 1000; ++idx) s+= idx; + std::cout << s << std::endl; +} + diff --git a/etc/test_mpi_exit_code.sh b/etc/test_mpi_exit_code.sh new file mode 100755 index 000000000..80fae0224 --- /dev/null +++ b/etc/test_mpi_exit_code.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Number of processes to use +nproc=$1 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +dir=$(pwd) +popd >/dev/null 2>&1 + +# Python work script +pyscript="${dir}/test_mpi_exit_code_work.py" + +# Run it +echo "=======================================================================" +echo "Testing MPI Abort() with $(which mpirun) on ${nproc} processes" +echo "=======================================================================" +com="mpirun -np ${nproc} python -m mpi4py ${pyscript}" +echo ${com} +eval ${com} + +# Verify non-zero exit code +status=$? +if (( $status == 0 )); then + echo "FAIL: Shell exit code was zero" + exit 1 +else + echo "Shell exit code was ${status}" + exit 0 +fi diff --git a/etc/test_mpi_exit_code_work.py b/etc/test_mpi_exit_code_work.py new file mode 100644 index 000000000..df02b9f56 --- /dev/null +++ b/etc/test_mpi_exit_code_work.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +"""Test MPI exit code. + +When running an MPI workflow, we want unhandled exceptions to trigger +an Abort on the world communicator. This prevents stale processes +from hanging in a deadlock case. This dummy script just raises +such an exception on the last process. + +""" + +import toast + + +def main(): + world, procs, rank = toast.mpi.get_world() + if rank == procs - 1: + msg = f"Testing unhandled exception on rank {rank}" + raise RuntimeError(msg) + if world is not None: + # Wait here to be killed + world.barrier() + + +if __name__ == "__main__": + world, procs, rank = toast.mpi.get_world() + with toast.mpi.exception_guard(comm=world, timeout=2): + main() diff --git a/etc/update_stats.py b/etc/update_stats.py new file mode 100755 index 000000000..1575ddac3 --- /dev/null +++ b/etc/update_stats.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import os +import sys +import json + + +original = sys.argv[1] + +data = dict() +do_backup = False +if os.path.isfile(original): + with open(original, "r") as f: + data = json.load(f) + do_backup = True + +for newfile in sys.argv[2:]: + with open(newfile, "r") as f: + newdata = json.load(f) + for jobtype, props in newdata.items(): + if jobtype not in data: + data[jobtype] = dict() + for case, stats in props.items(): + data[jobtype][case] = stats + +if do_backup: + backup = f"{original}.bak" + os.rename(original, backup) + +with open(original, "w") as f: + json.dump(data, f) diff --git a/packaging/conda/create_env.sh b/packaging/conda/create_env.sh new file mode 100644 index 000000000..0bfd24d4f --- /dev/null +++ b/packaging/conda/create_env.sh @@ -0,0 +1,53 @@ +# Variables set by calling code: +# - CONDA_EXE +# - ENVNAME +# + +# Activate the base environment +basedir=$(dirname $(dirname "${CONDA_EXE}")) +if [[ -e ${basedir}/etc/profile.d/conda.sh ]]; then + source ${basedir}/etc/profile.d/conda.sh +else + source /etc/profile.d/conda.sh +fi +conda deactivate +conda activate base + +conda env list + +# Determine whether the environment is a name or a +# full path. +env_noslash=$(echo "${ENVNAME}" | sed -e 's/\///g') + +is_path=no +if [ "${env_noslash}" != "${ENVNAME}" ]; then + # This was a path + is_path=yes + env_check="" + if [ -e "${ENVNAME}/bin/conda" ]; then + # It already exists + env_check="${ENVNAME}" + fi +else + env_check=$(conda env list | { grep "${ENVNAME} " || true; }) +fi + +if [ "x${env_check}" = "x" ]; then + # Environment does not yet exist. Create it. + echo "Creating new environment \"${ENVNAME}\"" + if [ ${is_path} = "no" ]; then + conda create --yes -n "${ENVNAME}" + else + conda create --yes -p "${ENVNAME}" + fi + echo "Activating environment \"${ENVNAME}\"" + conda activate "${ENVNAME}" + echo "Setting default channel in this env to conda-forge" + conda config --env --add channels conda-forge + conda config --env --set channel_priority strict +else + echo "Activating environment \"${ENVNAME}\"" + conda activate "${ENVNAME}" + conda env list +fi + diff --git a/packaging/conda/deps.txt b/packaging/conda/deps.txt new file mode 100644 index 000000000..7b9361c7a --- /dev/null +++ b/packaging/conda/deps.txt @@ -0,0 +1,21 @@ +cmake +autoconf +libtool +automake +psutil +cython +ruamel.yaml +pytest +tomlkit +traitlets +h5py +numpy +scipy +astropy +ephem +healpy +pshmem +coverage +pytest +coveralls +pytest-cov diff --git a/packaging/conda/extdeps.txt b/packaging/conda/extdeps.txt new file mode 100644 index 000000000..0d6933c82 --- /dev/null +++ b/packaging/conda/extdeps.txt @@ -0,0 +1,6 @@ +libopenblas=*=*openmp* +libblas=*=*openblas +fftw +libaatm +suitesparse +libflac diff --git a/packaging/conda/install_deps_conda.sh b/packaging/conda/install_deps_conda.sh new file mode 100755 index 000000000..a0f6f1915 --- /dev/null +++ b/packaging/conda/install_deps_conda.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +set -e + +envname=$1 + +# Explicit python version to use +pyversion=$2 +if [ "x${pyversion}" = "x" ]; then + pyversion=3.12 +fi + +# Install optional dependencies if desired +optional=$3 +if [ "x${optional}" = "xyes" ]; then + echo "Optional dependencies set to 'yes'" +else + echo "Optional dependencies set to 'no' or unspecified" +fi + +# Location of this script and dependencies +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +depsdir=$(dirname ${scriptdir})/deps + +if [ "x${CONDA_EXE}" = "x" ]; then + export CONDA_EXE=$(which conda) +fi +if [ "x${CONDA_EXE}" = "x" ]; then + echo "No conda executable found" + exit 1 +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The named environment will be created or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +export ENVNAME=${envname} + +# Create / activate env +. "${scriptdir}/create_env.sh" + +# Install conda packages + +pkgfiles="${scriptdir}/deps.txt ${scriptdir}/extdeps.txt" +if [ "x${optional}" = "xyes" ]; then + pkgfiles="${pkgfiles} ${scriptdir}/optdeps.txt" +fi + +pkglist="" +for pfile in ${pkgfiles}; do + plist=$(cat "${pfile}" | xargs -I % echo -n '"%" ') + pkglist="${pkglist} ${plist}" +done +pkglist="python=${pyversion} ${pkglist} compilers" +echo "Installing conda packages: ${pkglist}" +conda install --yes --update-all ${pkglist} +# The "cc" symlink breaks Crays... +rm -f "${CONDA_PREFIX}/bin/cc" + +# Reload the environment to pick up compiler environment variables +conda deactivate +conda activate "${ENVNAME}" + +# Install mpi4py, needed by some optional dependencies +. "${depsdir}/mpi4py.sh" + +if [ "x${optional}" != "xyes" ]; then + # we are done + exit 0 +fi + +# Now build the packages not available through conda + +python3 -m pip install qpoint + +# CC set by conda compilers +# CXX set by conda compilers +# FC set by conda compilers +if [ "x${MPICC}" = "x" ]; then + # The user did not specify MPI compilers, which means that + # the conda mpich package was installed + export MPICC=mpicc + export MPICXX=mpicxx + export MPIFC=mpif90 + export MPFCLIBS="-L${CONDA_PREFIX}/lib -lfmpich -lgfortran" +fi +export CFLAGS="-O3 -g -fPIC" +export CXXFLAGS="-O3 -g -fPIC" +export FCFLAGS="-O3 -g -fPIC" + +platform=$(python -c 'import sys; print(sys.platform)') +if [ ${platform} = "linux" ]; then + export OMPFLAGS="-fopenmp" + export SHLIBEXT="so" +else + export OMPFLAGS="" + export SHLIBEXT="dylib" +fi + +export DEPSDIR="${depsdir}" +export PREFIX="${CONDA_PREFIX}" +export MAKEJ=2 +export STATIC=no +export CLEANUP=no + +for pkg in "libmadam" "libconviqt"; do + . "${depsdir}/${pkg}.sh" +done + diff --git a/packaging/conda/install_deps_conda_external.sh b/packaging/conda/install_deps_conda_external.sh new file mode 100755 index 000000000..843ed2929 --- /dev/null +++ b/packaging/conda/install_deps_conda_external.sh @@ -0,0 +1,195 @@ +#!/bin/bash + +set -e + +envname=$1 + +# Explicit python version to use +pyversion=$2 +if [ "x${pyversion}" = "x" ]; then + pyversion=3.12 +fi + +# Install optional dependencies if desired +optional=$3 +if [ "x${optional}" = "xyes" ]; then + echo "Optional dependencies set to 'yes'" +else + echo "Optional dependencies set to 'no' or unspecified" +fi + +# Location of this script and dependencies +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +depsdir=$(dirname ${scriptdir})/deps + +if [ "x${CONDA_EXE}" = "x" ]; then + export CONDA_EXE=$(which conda) +fi +if [ "x${CONDA_EXE}" = "x" ]; then + echo "No conda executable found" + exit 1 +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The named environment will be created or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +export ENVNAME=${envname} + +# Create / activate env +. "${scriptdir}/create_env.sh" + +# Install conda packages. We only install the things needed from python. + +pkgfiles="${scriptdir}/deps.txt" +pkglist="" +for pfile in ${pkgfiles}; do + plist=$(cat "${pfile}" | xargs -I % echo -n '"%" ') + pkglist="${pkglist} ${plist}" +done +pkglist="python=${pyversion} ${pkglist}" +echo "Installing conda packages: ${pkglist}" +conda install --yes --update-all ${pkglist} + +# Reload the environment to pick up any environment variables +conda deactivate +conda activate "${ENVNAME}" + +# Add our compiled prefix into our search environment + +prepend_env () { + # This function is needed since trailing colons + # on some environment variables can cause major + # problems... + local envname="$1" + local envval="$2" + eval "local temp=\"\${$envname}\"" + if [ -z ${temp+x} ]; then + export ${envname}="${envval}" + else + export ${envname}="${envval}:${temp}" + fi +} + +export PREFIX="${CONDA_PREFIX}_ext" +mkdir -p "${PREFIX}/bin" +mkdir -p "${PREFIX}/include" +mkdir -p "${PREFIX}/lib" +prepend_env "PATH" "${PREFIX}/bin" +prepend_env "CPATH" "${PREFIX}/include" +prepend_env "LIBRARY_PATH" "${PREFIX}/lib" +prepend_env "LD_LIBRARY_PATH" "${PREFIX}/lib" +if [ ! -e "${PREFIX}/lib64" ]; then + ln -s "${PREFIX}/lib" "${PREFIX}/lib64" +fi + +# Compile dependencies with variables optionally set in the calling environment + +if [ "x${CC}" = "x" ]; then + export CC=gcc +fi +if [ "x${CXX}" = "x" ]; then + export CXX=g++ +fi +if [ "x${FC}" = "x" ]; then + export FC=gfortran +fi + +if [ "x${CFLAGS}" = "x" ]; then + export CFLAGS="-O3 -g -fPIC" +fi +if [ "x${CXXFLAGS}" = "x" ]; then + export CXXFLAGS="-O3 -g -fPIC" +fi +if [ "x${FCFLAGS}" = "x" ]; then + export FCFLAGS="-O3 -g -fPIC" +fi + +platform=$(python -c 'import sys; print(sys.platform)') +if [ ${platform} = "linux" ]; then + if [ "x${OMPFLAGS}" = "x" ]; then + export OMPFLAGS="-fopenmp" + fi + export SHLIBEXT="so" +else + export SHLIBEXT="dylib" +fi + +if [ "x${MAKEJ}" = "x" ]; then + export MAKEJ=2 +fi + +export DEPSDIR="${depsdir}" +export STATIC=no +export CLEANUP=no + +if [ "x${LAPACK_LIBRARIES}" = "x" ]; then + export BLAS_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + export LAPACK_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + . "${depsdir}/openblas.sh" +fi + +for pkg in cfitsio fftw libflac suitesparse libaatm; do + . "${depsdir}/${pkg}.sh" +done + +if [ "x${MPICC}" = "x" ]; then + # The user did not specify MPI compilers- try to use generic + # defaults. + echo "=====================================================================" + echo "" + echo "WARNING: If using custom compilers, you should have an" + echo "MPI installation with C, C++, and Fortran compiler wrappers." + echo "Set the MPICC, MPICXX, MPIFC, and MPIFCLIBS environment" + echo "variables before using this script. Assuming GNU compilers" + echo "and MPICH for now..." + export MPICC=mpicc + export MPICXX=mpicxx + export MPIFC=mpif90 + export MPFCLIBS="-L${CONDA_PREFIX}/lib -lfmpich -lgfortran" + echo "" + echo "=====================================================================" +fi + +# Install mpi4py, needed by some optional dependencies +. "${depsdir}/mpi4py.sh" + +if [ "x${optional}" != "xyes" ]; then + # we are done + exit 0 +fi + +for pkg in "libmadam" "libconviqt"; do + . "${depsdir}/${pkg}.sh" +done + +echo "=====================================================================" +echo "" +echo "Additional compiled dependencies installed next to conda" +echo "environment at '${PREFIX}'. You should prepend the following" +echo "locations to your environment before compiling toast:" +echo "" +echo " PATH --> '${PREFIX}/bin'" +echo " CPATH --> '${PREFIX}/include'" +echo " LIBRARY_PATH --> '${PREFIX}/lib'" +echo " LD_LIBRARY_PATH --> '${PREFIX}/lib'" +echo " PYTHONPATH --> '${PREFIX}/lib/python${pyversion}/site-packages'" +echo "" +echo "You can use the helper function in this directory:" +echo "" +echo " %> source packaging/conda/load_conda_external.sh" +echo " %> load_conda_ext ${ENVNAME}" +echo "" +echo "=====================================================================" + diff --git a/packaging/conda/load_conda_external.sh b/packaging/conda/load_conda_external.sh new file mode 100644 index 000000000..030ac61df --- /dev/null +++ b/packaging/conda/load_conda_external.sh @@ -0,0 +1,29 @@ +# This shell function loads a conda environment as well as +# the associated externally compiled packages. + +prepend_ext_env () { + # This function is needed since trailing colons + # on some environment variables can cause major + # problems... + local envname="$1" + local envval="$2" + eval "local temp=\"\${$envname}\"" + if [ -z ${temp+x} ]; then + export ${envname}="${envval}" + else + export ${envname}="${envval}:${temp}" + fi +} + +load_conda_ext () { + envname=$1 + conda activate "${envname}" + extprefix="${CONDA_PREFIX}_ext" + pyver=$(python3 --version 2>&1 | awk '{print $2}' | sed -e "s#\(.*\)\.\(.*\)\..*#\1.\2#") + prepend_ext_env "PATH" "${extprefix}/bin" + prepend_ext_env "CPATH" "${extprefix}/include" + prepend_ext_env "LIBRARY_PATH" "${extprefix}/lib" + prepend_ext_env "LD_LIBRARY_PATH" "${extprefix}/lib" + prepend_ext_env "PYTHONPATH" "${extprefix}/lib/python${pyver}/site-packages" + prepend_ext_env "PKG_CONFIG_PATH" "${extprefix}/lib/pkgconfig" +} diff --git a/packaging/conda/optdeps.txt b/packaging/conda/optdeps.txt new file mode 100644 index 000000000..aeff2bb50 --- /dev/null +++ b/packaging/conda/optdeps.txt @@ -0,0 +1,2 @@ +cfitsio +ducc0 diff --git a/packaging/deps/cfitsio.sh b/packaging/deps/cfitsio.sh new file mode 100644 index 000000000..4314be38c --- /dev/null +++ b/packaging/deps/cfitsio.sh @@ -0,0 +1,37 @@ +# Install CFITSIO + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - PREFIX +# - STATIC (yes/no) +# - CLEANUP (yes/no) + +cfitsio_version=4.6.2 +cfitsio_dir=cfitsio-${cfitsio_version} +cfitsio_pkg=${cfitsio_dir}.tar.gz + +echo "Fetching CFITSIO..." + +if [ ! -e ${cfitsio_pkg} ]; then + curl -SL https://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/${cfitsio_pkg} -o ${cfitsio_pkg} +fi + +echo "Building CFITSIO..." + +rm -rf ${cfitsio_dir} +tar xzf ${cfitsio_pkg} \ + && pushd ${cfitsio_dir} >/dev/null 2>&1 \ + && CC="${CC}" CFLAGS="${CFLAGS}" \ + ./configure \ + --enable-reentrant \ + --prefix="${PREFIX}" \ + && make stand_alone \ + && make utils \ + && if [ "x${STATIC}" != "xyes" ]; then make shared; fi \ + && make install \ + && popd >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${cfitsio_dir} +fi diff --git a/packaging/deps/fftw.sh b/packaging/deps/fftw.sh new file mode 100644 index 000000000..8813d8bb4 --- /dev/null +++ b/packaging/deps/fftw.sh @@ -0,0 +1,51 @@ +# Install FFTW + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - FC +# - FCFLAGS +# - OMPFLAGS +# - PREFIX +# - STATIC (yes/no) +# - MAKEJ +# - CLEANUP (yes/no) + +fftw_version=3.3.10 +fftw_dir=fftw-${fftw_version} +fftw_pkg=${fftw_dir}.tar.gz + +echo "Fetching FFTW..." + +if [ ! -e ${fftw_pkg} ]; then + curl -SL http://www.fftw.org/${fftw_pkg} -o ${fftw_pkg} +fi + +echo "Building FFTW..." + +shr="--enable-shared --disable-static" +if [ "${STATIC}" = "yes" ]; then + shr="--enable-static --disable-shared" +fi + +threads="--enable-openmp" +if [ "x${OMPFLAGS}" = "x" ]; then + threads="--enable-threads" +fi + +rm -rf ${fftw_dir} +tar xzf ${fftw_pkg} \ + && pushd ${fftw_dir} >/dev/null 2>&1 \ + && CC="${CC}" CFLAGS="${CFLAGS}" \ + FC="${FC}" FCFLAGS="${FCFLAGS}" \ + ./configure \ + --enable-fortran \ + ${threads} ${shr} \ + --prefix="${PREFIX}" \ + && make -j ${MAKEJ} \ + && make install \ + && popd >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${fftw_dir} +fi diff --git a/packaging/deps/libaatm.sh b/packaging/deps/libaatm.sh new file mode 100644 index 000000000..13ea1fe3b --- /dev/null +++ b/packaging/deps/libaatm.sh @@ -0,0 +1,43 @@ +# Install libaatm + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - CXX +# - CXXFLAGS +# - PREFIX +# - MAKEJ +# - CLEANUP (yes/no) + +aatm_version=1.1.0 +aatm_dir=libaatm-${aatm_version} +aatm_pkg=${aatm_dir}.tar.gz + +echo "Fetching libaatm..." + +if [ ! -e ${aatm_pkg} ]; then + curl -SL "https://github.com/hpc4cmb/libaatm/archive/${aatm_version}.tar.gz" -o "${aatm_pkg}" +fi + +echo "Building libaatm..." + +rm -rf ${aatm_dir} +tar xzf ${aatm_pkg} \ + && pushd ${aatm_dir} >/dev/null 2>&1 \ + && mkdir -p build \ + && pushd build >/dev/null 2>&1 \ + && cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + .. \ + && make -j ${MAKEJ} install \ + && popd >/dev/null 2>&1 \ + && popd >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${aatm_dir} +fi diff --git a/packaging/deps/libconviqt.sh b/packaging/deps/libconviqt.sh new file mode 100644 index 000000000..c0e116501 --- /dev/null +++ b/packaging/deps/libconviqt.sh @@ -0,0 +1,39 @@ +# Install libconviqt + +# Variables set by code sourcing this: +# - MPICC +# - CFLAGS +# - MPICXX +# - CXXFLAGS +# - PREFIX +# - STATIC (yes/no) +# - MAKEJ +# - CLEANUP (yes/no) + +conviqt_version=1.2.7 +conviqt_dir="libconviqt-${conviqt_version}" +conviqt_pkg="${conviqt_dir}.tar.gz" + +if [ ! -e ${conviqt_pkg} ]; then + curl -SL -o ${conviqt_pkg} https://github.com/hpc4cmb/libconviqt/archive/v${conviqt_version}.tar.gz +fi + +rm -rf ${conviqt_dir} +tar xzf ${conviqt_pkg} \ + && pushd ${conviqt_dir} >/dev/null \ + && ./autogen.sh \ + && CC="${MPICC}" CXX="${MPICXX}" MPICC="${MPICC}" MPICXX="${MPICXX}" \ + CFLAGS="${CFLAGS} -std=gnu99" CXXFLAGS="${CXXFLAGS}" \ + LDFLAGS="-L${PREFIX}/lib" \ + ./configure \ + --with-cfitsio="${PREFIX}" --prefix="${PREFIX}" \ + && make -j ${MAKEJ} \ + && make install \ + && pushd python >/dev/null \ + && python3 setup.py install --prefix="${PREFIX}" --old-and-unmanageable \ + && popd >/dev/null \ + && popd >/dev/null + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${conviqt_dir} +fi diff --git a/packaging/deps/libflac.sh b/packaging/deps/libflac.sh new file mode 100644 index 000000000..050383a23 --- /dev/null +++ b/packaging/deps/libflac.sh @@ -0,0 +1,58 @@ +# Install libFLAC + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - CXX +# - CXXFLAGS +# - PREFIX +# - MAKEJ +# - CLEANUP (yes/no) + +flac_version=1.5.0 +flac_dir=flac-${flac_version} +flac_pkg=${flac_dir}.tar.gz + +echo "Fetching libFLAC..." + +if [ ! -e ${flac_pkg} ]; then + curl -SL "https://github.com/xiph/flac/archive/refs/tags/${flac_version}.tar.gz" -o "${flac_pkg}" +fi + +echo "Building libFLAC..." + +shr="ON" +if [ "${STATIC}" = "yes" ]; then + shr="OFF" +fi + +rm -rf ${flac_dir} +tar xzf ${flac_pkg} \ + && pushd ${flac_dir} >/dev/null 2>&1 \ + && mkdir -p build \ + && pushd build >/dev/null 2>&1 \ + && cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DBUILD_DOCS=OFF \ + -DWITH_OGG=OFF \ + -DBUILD_CXXLIBS=OFF \ + -DBUILD_PROGRAMS=OFF \ + -DBUILD_UTILS=OFF \ + -DBUILD_TESTING=OFF \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_SHARED_LIBS=${shr} \ + -DINSTALL_MANPAGES=OFF \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + .. \ + && make -j ${MAKEJ} install \ + && popd >/dev/null 2>&1 \ + && popd >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${flac_dir} +fi diff --git a/packaging/deps/libmadam.sh b/packaging/deps/libmadam.sh new file mode 100644 index 000000000..e6e1ed99d --- /dev/null +++ b/packaging/deps/libmadam.sh @@ -0,0 +1,44 @@ +# Install libmadam + +# Variables set by code sourcing this: +# - MPICC +# - CFLAGS +# - MPIFC +# - FCFLAGS +# - MPFCLIBS +# - PREFIX +# - STATIC (yes/no) +# - MAKEJ +# - CLEANUP (yes/no) + +# LDFLAGS="-L${PREFIX}/lib -lfmpich -lgfortran" \ + +madam_version=1.0.2 +madam_dir="libmadam-${madam_version}" +madam_pkg=${madam_dir}.tar.bz2 + +if [ ! -e ${madam_pkg} ]; then + curl -SL -o ${madam_pkg} https://github.com/hpc4cmb/libmadam/releases/download/v${madam_version}/${madam_pkg} +fi + +rm -rf ${madam_dir} +tar xjf ${madam_pkg} \ + && pushd ${madam_dir} >/dev/null \ + && FC="${MPIFC}" MPIFC="${MPIFC}" FCFLAGS="${FCFLAGS}" \ + CC="${MPICC}" MPICC="${MPICC}" CFLAGS="${CFLAGS}" \ + LDFLAGS="${MPFCLIBS}" \ + ./configure --with-cfitsio="${PREFIX}" \ + --with-fftw="${PREFIX}" \ + --with-blas="-L${PREFIX}/lib -lopenblas" \ + --with-lapack="-L${PREFIX}/lib -lopenblas" \ + --prefix="${PREFIX}" \ + && make -j ${MAKEJ} \ + && make install \ + && pushd python >/dev/null \ + && python3 setup.py install --prefix="${PREFIX}" --old-and-unmanageable \ + && popd >/dev/null \ + && popd >/dev/null + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${madam_dir} +fi diff --git a/packaging/deps/mpi4py.sh b/packaging/deps/mpi4py.sh new file mode 100644 index 000000000..eb009f0e2 --- /dev/null +++ b/packaging/deps/mpi4py.sh @@ -0,0 +1,20 @@ +# Variables set by calling code: +# - MPICC (optional) +# + +# Install mpi4py + +echo "Installing mpi4py..." +if [ "x${MPICC}" = "x" ]; then + echo "The MPICC environment variable is not set. Installing mpi4py" + echo "from the conda package, rather than building from source." + if [ "x$(which conda)" = "x" ]; then + echo "Conda not available- giving up!" + else + conda install --yes mpich mpi4py + fi +else + echo "Building mpi4py with MPICC=\"${MPICC}\"" + CFLAGS="-O2 -g -fPIC" pip install --force-reinstall --no-cache-dir --no-binary=mpi4py mpi4py +fi + diff --git a/packaging/deps/openblas.sh b/packaging/deps/openblas.sh new file mode 100644 index 000000000..bcc2852ed --- /dev/null +++ b/packaging/deps/openblas.sh @@ -0,0 +1,53 @@ +# Install Openblas + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - FC +# - FCFLAGS +# - FCLIBS +# - OMPFLAGS +# - PREFIX +# - STATIC (yes/no) +# - MAKEJ +# - CLEANUP (yes/no) + +openblas_version=0.3.29 +openblas_dir=OpenBLAS-${openblas_version} +openblas_pkg=${openblas_dir}.tar.gz + +if [ ! -e ${openblas_pkg} ]; then + echo "Fetching OpenBLAS..." + curl -SL https://github.com/xianyi/OpenBLAS/archive/v${openblas_version}.tar.gz -o ${openblas_pkg} +fi + +echo "Building OpenBLAS..." + +shr="NO_STATIC=1" +targ="libs netlib shared" +if [ "${STATIC}" = "yes" ]; then + shr="NO_SHARED=1" + targ="libs netlib" +fi + +omp="USE_OPENMP=1" +if [ "x${OMPFLAGS}" = "x" ]; then + omp="USE_OPENMP=0" +fi + +start_dir=$(pwd) +rm -rf ${openblas_dir} +tar xzf ${openblas_pkg} \ + && pushd ${openblas_dir} >/dev/null 2>&1 \ + && make ${omp} ${shr} \ + MAKE_NB_JOBS=${MAKEJ} \ + CC="${CC}" FC="${FC}" DYNAMIC_ARCH=1 TARGET=GENERIC \ + COMMON_OPT="${CFLAGS}" FCOMMON_OPT="${FCFLAGS}" \ + EXTRALIB="${OMPFLAGS} -lm ${FCLIBS}" ${targ} \ + && make ${shr} DYNAMIC_ARCH=1 TARGET=GENERIC PREFIX="${PREFIX}" install \ + && popd >/dev/null 2>&1 +pushd "${start_dir}" >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${openblas_dir} +fi diff --git a/packaging/deps/suitesparse.sh b/packaging/deps/suitesparse.sh new file mode 100644 index 000000000..29f3909dd --- /dev/null +++ b/packaging/deps/suitesparse.sh @@ -0,0 +1,60 @@ +# Install SuiteSparse - only the pieces we need. + +# Variables set by code sourcing this: +# - CC +# - CFLAGS +# - CXX +# - CXXFLAGS +# - FC +# - FCFLAGS +# - FCLIBS +# - OMPFLAGS +# - BLAS_LIBRARIES +# - LAPACK_LIBRARIES +# - PREFIX +# - DEPSDIR (to find patches) +# - MAKEJ +# - STATIC (yes/no) +# - CLEANUP (yes/no) + +ssparse_version=7.10.2 +ssparse_dir=SuiteSparse-${ssparse_version} +ssparse_pkg=${ssparse_dir}.tar.gz + +echo "Fetching SuiteSparse..." + +if [ ! -e ${ssparse_pkg} ]; then + curl -SL https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v${ssparse_version}.tar.gz -o ${ssparse_pkg} +fi + +echo "Building SuiteSparse..." + +shr="-DNSTATIC:BOOL=ON -DBLA_STATIC:BOOL=OFF" +if [ "${STATIC}" = "yes" ]; then + shr="-DNSTATIC:BOOL=OFF -DBLA_STATIC:BOOL=ON" +fi + +rm -rf ${ssparse_dir} +tar xzf ${ssparse_pkg} \ + && pushd ${ssparse_dir} >/dev/null 2>&1 \ + && cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_Fortran_COMPILER="${FC}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_Fortran_FLAGS="${FCFLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_INSTALL_PATH="${PREFIX}" \ + -DCMAKE_BUILD_TYPE=Release ${shr} \ + -DBLAS_LIBRARIES="${BLAS_LIBRARIES}" \ + -DLAPACK_LIBRARIES="${LAPACK_LIBRARIES}" ${BLA_OPTIONS} \ + -DSUITESPARSE_ENABLE_PROJECTS="cholmod" \ + -S . -B build \ + && cmake --build build \ + && cmake --install build \ + && popd >/dev/null 2>&1 + +if [ "x${CLEANUP}" = "xyes" ]; then + rm -rf ${ssparse_dir} +fi diff --git a/packaging/venv/deps.txt b/packaging/venv/deps.txt new file mode 100644 index 000000000..2cdbef5e3 --- /dev/null +++ b/packaging/venv/deps.txt @@ -0,0 +1,21 @@ +cmake +autoconf +libtool +automake +psutil +cython +pytest +tomlkit +traitlets +h5py +numpy +scipy +astropy +ephem +healpy +pshmem +coverage +pytest +coveralls +pytest-cov +ducc0 diff --git a/packaging/venv/install_deps_venv.sh b/packaging/venv/install_deps_venv.sh new file mode 100755 index 000000000..3494e05d1 --- /dev/null +++ b/packaging/venv/install_deps_venv.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +set -e + +envname=$1 + +# Install optional dependencies if desired +optional=$2 +if [ "x${optional}" = "xyes" ]; then + echo "Optional dependencies set to 'yes'" +else + echo "Optional dependencies set to 'no' or unspecified" +fi + +# Static linking? +static=$3 +if [ "x${optional}" = "xyes" ]; then + echo "Static linking set to 'yes'" +else + echo "Static linking set to 'no' or unspecified" +fi + +# Location of this script and dependencies +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +depsdir=$(dirname ${scriptdir})/deps + +PY_EXE=$(which python3) +if [ "x${PY_EXE}" = "x" ]; then + echo "No python3 executable found" + exit 1 +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The named environment will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +if [ ! -d "${envname}" ]; then + # Create it + python3 -m venv "${envname}" +fi + +if [ ! -e "${envname}/bin/activate" ]; then + echo "Environment \"${envname}\" exists, but activate script not found" + exit 1 +fi + +. "${envname}/bin/activate" +python3 -m pip install install --upgrade pip setuptools wheel + +# Install packages + +pkglist=$(cat "${scriptdir}/deps.txt" | xargs -I % echo -n '% ') +echo "Installing pip packages: ${pkglist}" +python3 -m pip install --no-input ${pkglist} + +# Add our compiled prefix into our search environment + +export PREFIX="${envname}" + +prepend_env () { + # This function is needed since trailing colons + # on some environment variables can cause major + # problems... + local envname="$1" + local envval="$2" + eval "local temp=\"\${$envname}\"" + if [ -z ${temp+x} ]; then + export ${envname}="${envval}" + else + export ${envname}="${envval}:${temp}" + fi +} + +mkdir -p "${PREFIX}/include" +mkdir -p "${PREFIX}/lib" +prepend_env "PATH" "${PREFIX}/bin" +prepend_env "CPATH" "${PREFIX}/include" +prepend_env "LIBRARY_PATH" "${PREFIX}/lib" +prepend_env "LD_LIBRARY_PATH" "${PREFIX}/lib" +if [ ! -e "${PREFIX}/lib64" ]; then + ln -s "${PREFIX}/lib" "${PREFIX}/lib64" +fi + +# Compile dependencies with variables optionally set in the calling environment + +if [ "x${CC}" = "x" ]; then + export CC=gcc +fi +if [ "x${CXX}" = "x" ]; then + export CXX=g++ +fi +if [ "x${FC}" = "x" ]; then + export FC=gfortran +fi + +if [ "x${CFLAGS}" = "x" ]; then + export CFLAGS="-O3 -g -fPIC" +fi +if [ "x${CXXFLAGS}" = "x" ]; then + export CXXFLAGS="-O3 -g -fPIC" +fi +if [ "x${FCFLAGS}" = "x" ]; then + export FCFLAGS="-O3 -g -fPIC" +fi + +platform=$(python -c 'import sys; print(sys.platform)') +if [ ${platform} = "linux" ]; then + if [ "x${OMPFLAGS}" = "x" ]; then + export OMPFLAGS="-fopenmp" + fi + export SHLIBEXT="so" +else + export SHLIBEXT="dylib" +fi + +if [ "x${MAKEJ}" = "x" ]; then + export MAKEJ=2 +fi + +export DEPSDIR="${depsdir}" +export STATIC=${static} +export CLEANUP=no + +if [ "x${LAPACK_LIBRARIES}" = "x" ]; then + export BLAS_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + export LAPACK_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + . "${depsdir}/openblas.sh" +fi + +for pkg in cfitsio fftw libflac suitesparse libaatm; do + . "${depsdir}/${pkg}.sh" +done + +# Install mpi4py, needed by some optional dependencies +. "${depsdir}/mpi4py.sh" + +if [ "x${optional}" != "xyes" ]; then + # we are done + exit 0 +fi + +# Now build the extra packages + +if [ "x${MPICC}" = "x" ]; then + # This should have already raised an error installing mpi4py... + export MPICC=mpicc +fi +if [ "x${MPICC}" = "x" ]; then + export MPICXX=mpicxx +fi +if [ "x${MPIFC}" = "x" ]; then + export MPIFC=mpif90 +fi +if [ "x${MPFCLIBS}" = "x" ]; then + export MPFCLIBS="-lfmpich -lgfortran" +fi + +for pkg in "libmadam" "libconviqt"; do + . "${depsdir}/${pkg}.sh" +done + diff --git a/packaging/wheels/build_requirements.txt b/packaging/wheels/build_requirements.txt new file mode 100644 index 000000000..0191a12be --- /dev/null +++ b/packaging/wheels/build_requirements.txt @@ -0,0 +1,15 @@ +# Build dependencies installed after any low-level / pinned packages +tomlkit +traitlets>=5.0 +numpy<2.3 +scipy +matplotlib +psutil +h5py +pshmem>=1.2.1 +pyyaml +astropy +healpy +ephem +qpoint +spt3g diff --git a/wheels/build_sdist.sh b/packaging/wheels/build_sdist.sh similarity index 100% rename from wheels/build_sdist.sh rename to packaging/wheels/build_sdist.sh diff --git a/packaging/wheels/cibw_run_tests.sh b/packaging/wheels/cibw_run_tests.sh new file mode 100755 index 000000000..7cc2aa973 --- /dev/null +++ b/packaging/wheels/cibw_run_tests.sh @@ -0,0 +1,19 @@ +# This file is sourced by cibuildwheel using /bin/sh + +# echo "Skipping tests to produce wheel artifacts for local testing" + +echo "=======================================================================" +echo "Running serial tests with MPI disabled" +echo "=======================================================================" +MPI_DISABLE=1 python -c 'import toast.tests; toast.tests.run()' + +# echo "=======================================================================" +# echo "Running MPI tests with $(which mpirun)" +# echo "*** FIXME: currently MPI run inside the cibuildwheel docker containers" +# echo "*** spawns MPI processes independently (they each have a comm world of" +# echo "*** one process. So we are not really testing much. Change this to" +# echo "*** two processes once it works." +# echo "=======================================================================" +# com="mpirun -np 1 python -m mpi4py -c 'import toast.tests; toast.tests.run()'" +# echo ${com} +# eval ${com} diff --git a/packaging/wheels/install_deps_linux.sh b/packaging/wheels/install_deps_linux.sh new file mode 100755 index 000000000..bd52fd3cd --- /dev/null +++ b/packaging/wheels/install_deps_linux.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# +# This script is designed to run within a container managed by cibuildwheel. +# This will run in a manylinux container. +# +# The purpose of this script is to install TOAST dependency libraries that will be +# bundled with our compiled extension. +# + +set -e + +toolchain=$1 +prefix=$2 +static=$3 + +if [ "x${toolchain}" = "x" ]; then + toolchain="gcc" +fi + +if [ "x${prefix}" = "x" ]; then + prefix=/usr/local +fi + +if [ "x${static}" = "x" ]; then + static="yes" +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +echo "Wheel script directory = ${scriptdir}" + +# Location of dependency scripts +depsdir=$(dirname ${scriptdir})/deps + +# Build options + +if [ "x${toolchain}" = "xgcc" ]; then + export CC=gcc + export CXX=g++ + export FC=gfortran + + export CFLAGS="-O3 -fPIC -pthread" + export FCFLAGS="-O3 -fPIC -pthread" + export CXXFLAGS="-O3 -fPIC -pthread -std=c++11" + export FCLIBS="-lgfortran" + export OMPFLAGS="-fopenmp" +else + if [ "x${toolchain}" = "xllvm" ]; then + export CC=clang-17 + export CXX=clang++-17 + export FC=gfortran + + export CFLAGS="-O3 -fPIC -pthread" + export FCFLAGS="-O3 -fPIC -pthread" + export CXXFLAGS="-O3 -fPIC -pthread -std=c++11 -stdlib=libc++" + export FCLIBS="-L/usr/lib/llvm-17/lib /usr/lib/x86_64-linux-gnu/libgfortran.so.5" + export OMPFLAGS="-fopenmp" + else + echo "Unsupported toolchain \"${toolchain}\"" + exit 1 + fi +fi + +# Update pip +pip install --upgrade pip + +# Install a couple of base packages that are always required +pip install -v cmake wheel + +pyver=$(python3 --version 2>&1 | awk '{print $2}' | sed -e "s#\(.*\)\.\(.*\)\..*#\1.\2#") + +# Install build requirements. +CC="${CC}" CFLAGS="${CFLAGS}" pip install -v -r "${scriptdir}/build_requirements.txt" + +# Build compiled dependencies + +# For testing locally +# export MAKEJ=8 +export MAKEJ=2 +export PREFIX="${prefix}" +export DEPSDIR="${depsdir}" +export STATIC="${static}" +export SHLIBEXT="so" +export CLEANUP=yes + +export BLAS_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" +export LAPACK_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + +for pkg in openblas fftw libflac suitesparse libaatm; do + source "${depsdir}/${pkg}.sh" +done diff --git a/packaging/wheels/install_deps_osx.sh b/packaging/wheels/install_deps_osx.sh new file mode 100755 index 000000000..82fe9d2db --- /dev/null +++ b/packaging/wheels/install_deps_osx.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# +# This script is designed to run within a container managed by cibuildwheel. +# This will use a recent version of OS X. +# +# The purpose of this script is to install TOAST dependency libraries that will be +# bundled with our compiled extension. +# + +set -e + +prefix=$2 + +if [ "x${prefix}" = "x" ]; then + prefix=/usr/local +fi + +export PREFIX="${prefix}" + +# If we are running on github CI, ensure that permissions +# are set on /usr/local. See: +# https://github.com/actions/runner-images/issues/9272 +sudo chown -R runner:admin /usr/local/ + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +echo "Wheel script directory = ${scriptdir}" + +# Location of dependency scripts +depsdir=$(dirname ${scriptdir})/deps + +# Are we using gcc? Useful for OpenMP. +# use_gcc=yes +use_gcc=no +gcc_version=14 + +# Build options. + +if [ "x${use_gcc}" = "xyes" ]; then + export CC=gcc-${gcc_version} + export CXX=g++-${gcc_version} + export FC=gfortran-${gcc_version} + export CFLAGS="-O3 -fPIC" + export FCFLAGS="-O3 -fPIC" + export CXXFLAGS="-O3 -fPIC -std=c++11" + export FCLIBS="-lgfortran" + export OMPFLAGS="-fopenmp" +else + # Set the deployment target based on how python was built + export MACOSX_DEPLOYMENT_TARGET=$(python3 -c "import sysconfig as s; print(s.get_config_vars()['MACOSX_DEPLOYMENT_TARGET'])") + echo "Using MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}" + export CC=clang + export CXX=clang++ + export FC= + export CFLAGS="-O3 -fPIC" + export CXXFLAGS="-O3 -fPIC -std=c++11 -stdlib=libc++" + export FCFLAGS="" + export FCLIBS="" + export OMPFLAGS="" +fi + +# Install any pre-built dependencies with homebrew + +# Force uninstall flac tools, to avoid conflicts with our +# custom compiled version. +brew uninstall -f --ignore-dependencies flac libogg libsndfile libvorbis opusfile sox +if [ "x${use_gcc}" = "xyes" ]; then + brew install gcc@${gcc_version} +fi + +# Update pip +pip install --upgrade pip + +# Install a couple of base packages that are always required +pip install -v wheel + +pyver=$(python3 --version 2>&1 | awk '{print $2}' | sed -e "s#\(.*\)\.\(.*\)\..*#\1.\2#") + +# Install build requirements. +CC="${CC}" CFLAGS="${CFLAGS}" pip install -v -r "${scriptdir}/build_requirements.txt" + +# Build compiled dependencies + +export MAKEJ=2 +export DEPSDIR="${depsdir}" +export STATIC=no +export SHLIBEXT="dylib" +export CLEANUP=yes + +export BLAS_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" +export LAPACK_LIBRARIES="-L${PREFIX}/lib -lopenblas ${OMPFLAGS} -lm ${FCLIBS}" + +for pkg in openblas fftw libflac suitesparse libaatm; do + source "${depsdir}/${pkg}.sh" +done diff --git a/packaging/wheels/test_local_cibuildwheel.sh b/packaging/wheels/test_local_cibuildwheel.sh new file mode 100755 index 000000000..08fc71664 --- /dev/null +++ b/packaging/wheels/test_local_cibuildwheel.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Before running this from the toast git checkout directory, +# you should pip install cibuildwheel + +export CIBW_BUILD="cp312-manylinux_x86_64" +export CIBW_MANYLINUX_X86_64_IMAGE="manylinux_2_28" +export CIBW_BUILD_VERBOSITY=3 +export CIBW_ENVIRONMENT_LINUX="TOAST_BUILD_BLAS_LIBRARIES='-L/usr/local/lib -lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_LAPACK_LIBRARIES='-L/usr/local/lib -lopenblas -fopenmp -lm -lgfortran' TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON TOAST_BUILD_TOAST_STATIC_DEPS=ON TOAST_BUILD_FFTW_ROOT=/usr/local TOAST_BUILD_AATM_ROOT=/usr/local TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS=/usr/local/include TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS=/usr/local/lib" +export CIBW_BEFORE_BUILD_LINUX=./packaging/wheels/install_deps_linux.sh +export CIBW_BEFORE_TEST="export OMP_NUM_THREADS=2" +export CIBW_TEST_COMMAND=". {project}/packaging/wheels/cibw_run_tests.sh" + +# Get the current date for logging +now=$(date "+%Y-%m-%d_%H:%M:%S") + +# Run it +cibuildwheel --platform linux --output-dir wheelhouse . 2>&1 | tee log_${now} + diff --git a/packaging/wheels/test_local_linux.sh b/packaging/wheels/test_local_linux.sh new file mode 100755 index 000000000..188bf362d --- /dev/null +++ b/packaging/wheels/test_local_linux.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# This script is used to build toast and dependencies and install them +# into the currently active virtualenv. + +set -e + +# Location of the source tree +pushd $(dirname $0) >/dev/null 2>&1 +topdir=$(dirname $(pwd)) +popd >/dev/null 2>&1 + +venv_path=$1 +if [ "x${venv_path}" = "x" ]; then + echo "Usage: $0 " + echo " If the path to the virtualenv exists, it will be activated." + echo " Otherwise it will be created." + exit 1 +fi + +toolchain=$2 +if [ "x${toolchain}" = "x" ]; then + toolchain="gcc" +fi + +# Deactivate any current venv +if [ "x$(type -t deactivate)" != "x" ]; then + deactivate +fi + +echo "Using compiler '${toolchain}'" + +if [ -d ${venv_path} ]; then + echo "Virtualenv \"${venv_path}\" already exists, activating" +else + echo "Creating virtualenv \"${venv_path}\"" + eval "python3 -m venv \"${venv_path}\"" +fi +source "${venv_path}/bin/activate" +venv_py_ver=$(python3 --version | awk '{print $2}') + +# Install our dependencies +eval "${topdir}/packaging/wheels/install_deps_linux.sh" "${toolchain}" "${venv_path}" "no" + +# Look for our dependencies in the virtualenv +export LD_LIBRARY_PATH="${venv_path}/lib" +export CPATH="${venv_path}/include" + +if [ "x${toolchain}" = "xgcc" ]; then + CC=gcc + CXX=g++ + CFLAGS="-O3 -fPIC -pthread" + CXXFLAGS="-O3 -fPIC -pthread -std=c++11" + FCLIBS="-lgfortran" +else + if [ "x${toolchain}" = "xllvm" ]; then + CC=clang-17 + CXX=clang++-17 + CFLAGS="-O3 -fPIC -pthread" + CXXFLAGS="-O3 -fPIC -pthread -std=c++11 -stdlib=libc++" + FCLIBS="-lgfortran" + else + echo "Unsupported toolchain \"${toolchain}\"" + exit 1 + fi +fi + +# Set up toast build options +export TOAST_BUILD_CMAKE_C_COMPILER="${CC}" +export TOAST_BUILD_CMAKE_CXX_COMPILER="${CXX}" +export TOAST_BUILD_CMAKE_C_FLAGS="${CFLAGS} -I${venv_path}/include" +export TOAST_BUILD_CMAKE_CXX_FLAGS="${CXXFLAGS} -I${venv_path}/include" +export TOAST_BUILD_DISABLE_OPENMP_TARGET=ON +export TOAST_BUILD_BLAS_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm ${FCLIBS}" +export TOAST_BUILD_LAPACK_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm ${FCLIBS}" +export TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON +export TOAST_BUILD_AATM_ROOT="${venv_path}" +export TOAST_BUILD_FFTW_ROOT="${venv_path}" +export TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS="${venv_path}/include" +export TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS="${venv_path}/lib" +export TOAST_BUILD_CMAKE_LIBRARY_PATH="${venv_path}/lib" +# export TOAST_BUILD_TOAST_STATIC_DEPS=ON + +# Install it +pushd "${topdir}" 2>&1 >/dev/null +python3 -m pip install -vvv . +popd 2>&1 >/dev/null + +# Run tests +python3 -c 'import toast.tests; toast.tests.run()' diff --git a/packaging/wheels/test_local_macos.sh b/packaging/wheels/test_local_macos.sh new file mode 100755 index 000000000..c23e2c7dd --- /dev/null +++ b/packaging/wheels/test_local_macos.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +# This script tests the local use of setup.py on MacOS. It assumes +# that you have homebrew installed and have the "brew" command in +# your PATH. +# +# This script takes one argument, which is the path to the virtualenv +# to use for installation. If that path does not exist, it will be +# created. +# + +set -e + +# Location of the source tree +pushd $(dirname $0) >/dev/null 2>&1 +topdir=$(dirname $(pwd)) +popd >/dev/null 2>&1 + +brew_com=$(which brew) +if [ "x${brew_com}" = "x" ]; then + echo "Homebrew must be installed and the brew command available" + exit 1 +fi + +venv_path=$1 +if [ "x${venv_path}" = "x" ]; then + echo "Usage: $0 " + echo " If the path to the virtualenv exists, it will be activated." + echo " Otherwise it will be created." + exit 1 +fi + +# Deactivate any current venv +if [ "x$(type -t deactivate)" != "x" ]; then + deactivate +fi + +# Path to homebrew +brew_root=$(dirname $(dirname ${brew_com})) +echo "Using homebrew installation in ${brew_root}" + +# Export compiler information +# export CC=clang +# export CXX=clang++ +# export CFLAGS="-O3 -fPIC" +# export CXXFLAGS="-O3 -fPIC -std=c++11 -stdlib=libc++" +export CC=gcc-12 +export CXX=g++-12 +export CFLAGS="-O3 -fPIC" +export CXXFLAGS="-O3 -fPIC -std=c++11" + +# Use homebrew python for development files and compiler +eval ${brew_com} install python3 gcc@12 + +brew_py="${brew_root}/opt/python@3/bin/python3" +brew_py_ver=$(eval ${brew_py} --version | awk '{print $2}') +echo "Using python ${brew_py}, version ${brew_py_ver}" + +if [ -d ${venv_path} ]; then + echo "Virtualenv \"${venv_path}\" already exists, activating" + source "${venv_path}/bin/activate" + venv_py_ver=$(python3 --version | awk '{print $2}') + if [ "${venv_py_ver}" != "${brew_py_ver}" ]; then + echo "Virtualenv python version ${venv_py_ver} does not match" + echo "homebrew python version ${brew_py_ver}. Remove this" + echo "virtualenv or use a different path." + exit 1 + fi +else + echo "Creating virtualenv \"${venv_path}\"" + eval "${brew_py} -m venv \"${venv_path}\"" + source "${venv_path}/bin/activate" +fi + +# Install our dependencies +eval "${topdir}/packaging/wheels/install_deps_osx.sh" "${venv_path}" + +python3 -m pip install delocate + +# Look for our dependencies in the virtualenv +export LD_LIBRARY_PATH="${venv_path}/lib" +export DYLD_LIBRARY_PATH="${venv_path}/lib" +export CPATH="${venv_path}/include" + +# Set up toast build options +export TOAST_BUILD_CMAKE_C_COMPILER="${CC}" +export TOAST_BUILD_CMAKE_CXX_COMPILER="${CXX}" +export TOAST_BUILD_CMAKE_C_FLAGS="${CFLAGS} -I${venv_path}/include" +export TOAST_BUILD_BLAS_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm -lgfortran" +export TOAST_BUILD_LAPACK_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm -lgfortran" +export TOAST_BUILD_CMAKE_CXX_FLAGS="${CXXFLAGS} -I${venv_path}/include" +export TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON +export TOAST_BUILD_AATM_ROOT="${venv_path}" +export TOAST_BUILD_FFTW_ROOT="${venv_path}" +export TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS="${venv_path}/include" +export TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS="${venv_path}/lib" +export TOAST_BUILD_CMAKE_LIBRARY_PATH="${venv_path}/lib" +export TOAST_BUILD_TOAST_STATIC_DEPS=ON + +# Now build a wheel +pushd "${topdir}" >/dev/null 2>&1 +rm -rf build/temp_wheels/*.whl +python3 setup.py clean +python3 -m pip wheel --wheel-dir=build/temp_wheels --no-deps -vvv . +popd >/dev/null 2>&1 + +# The file +input_wheel=$(ls ${topdir}/build/temp_wheels/*.whl) +wheel_file=$(basename ${input_wheel}) + +# Repair it +delocate-listdeps ${input_wheel} \ +&& delocate-wheel -w ${topdir} ${input_wheel} + +# Install it +python3 -m pip install ${topdir}/${wheel_file} + +# Run tests +python3 -c 'import toast.tests; toast.tests.run()' diff --git a/pipelines/CMakeLists.txt b/pipelines/CMakeLists.txt deleted file mode 100644 index 5fb1fc7f4..000000000 --- a/pipelines/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ - -# Install all the scripts into the bin directory - -install(PROGRAMS - toast_env_test.py - toast_cache_test.py - toast_cov_invert.py - toast_cov_rcond.py - toast_fake_focalplane.py - toast_ground_schedule.py - toast_satellite_sim.py - toast_ground_sim.py - toast_ground_sim_simple.py - toast_benchmark.py - DESTINATION bin -) diff --git a/pipelines/toast_benchmark.py b/pipelines/toast_benchmark.py deleted file mode 100644 index 2dd29d7f8..000000000 --- a/pipelines/toast_benchmark.py +++ /dev/null @@ -1,1220 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -""" -This script dynamically builds a workflow tailored to the size of the communicator. -""" - -# This is the maximum random time in seconds for every process to sleep before starting. -# This should be long enough to avoid filesystem contention when loading shared -# libraries and python modules, but short enough that the scheduler does not think that -# MPI has hung and kills the job. -startup_delay = 2.0 - -# These are builtin modules, hopefully fast to load. -import random -import time - -wait = random.uniform(0.0, startup_delay) -time.sleep(wait) - -from toast.mpi import MPI - -# Now import the remaining modules -import os -import sys -import re -import copy -import argparse -import traceback -import pickle - -from datetime import datetime - -import psutil - -import numpy as np - -import healpy as hp - -from toast.mpi import get_world, Comm - -from toast.dist import distribute_uniform, Data, distribute_discrete - -from toast.utils import Logger, Environment, memreport - -from toast.timing import function_timer, GlobalTimers, Timer, gather_timers -from toast.timing import dump as dump_timing - -from toast.todmap import TODGround - -from toast import pipeline_tools - -from toast import rng - -from toast.pipeline_tools import Focalplane - -from toast.tod.sim_focalplane import hex_pol_angles_qu, hex_layout, hex_nring - -from toast.schedule import run_scheduler - - -# This function is part of the package in TOAST 3.0. Remove this here when porting. - - -def fake_hexagon_focalplane( - n_pix=7, - width_deg=5.0, - samplerate=1.0, - epsilon=0.0, - net=1.0, - fmin=0.0, - alpha=1.0, - fknee=0.05, -): - pol_A = hex_pol_angles_qu(n_pix, offset=0.0) - pol_B = hex_pol_angles_qu(n_pix, offset=90.0) - quat_A = hex_layout(n_pix, width_deg, "D", "A", pol_A) - quat_B = hex_layout(n_pix, width_deg, "D", "B", pol_B) - - det_data = dict(quat_A) - det_data.update(quat_B) - - nrings = hex_nring(n_pix) - detfwhm = 0.5 * 60.0 * width_deg / (2 * nrings - 1) - - for det in det_data.keys(): - det_data[det]["pol_leakage"] = epsilon - det_data[det]["fmin"] = fmin - det_data[det]["fknee"] = fknee - det_data[det]["alpha"] = alpha - det_data[det]["NET"] = net - det_data[det]["fwhm_arcmin"] = detfwhm - det_data[det]["fsample"] = samplerate - - return Focalplane(detector_data=det_data, sample_rate=samplerate) - - -def get_node_mem(mpicomm, node_rank): - avail = 2 ** 62 - if node_rank == 0: - vmem = psutil.virtual_memory()._asdict() - avail = vmem["available"] - if mpicomm is not None: - avail = mpicomm.allreduce(avail, op=MPI.MIN) - return int(avail) - - -def sample_distribution( - rank, procs_per_node, bytes_per_node, total_samples, sample_rate -): - # For this benchmark, we start by ramping up to a realistic number of detectors for - # one day of data. Then we extend the timespan to achieve the desired number of - # samples. - - log = Logger.get() - - # Hex-packed 127 pixels (6 rings) times two dets per pixel. - # max_detector = 254 - - # Hex-packed 1027 pixels (18 rings) times two dets per pixel. - max_detector = 2054 - - # Minimum time span (one day) - min_time_samples = int(24 * 3600 * sample_rate) - - # For the minimum time span, scale up the number of detectors to reach the - # requested total sample size. - - n_detector = 1 - test_samples = n_detector * min_time_samples - - while test_samples < total_samples and n_detector < max_detector: - n_detector += 1 - test_samples = n_detector * min_time_samples - - if rank == 0: - log.debug( - " Dist total = {}, using {} detectors at min time samples = {}".format( - total_samples, n_detector, min_time_samples - ) - ) - - # For this number of detectors, determine the group size needed to fit the - # minimum number of samples in memory. In practice, one day will actually be - # split up into multiple observations. However, sizing the groups this way ensures - # that each group will have multiple observations and improve the load balancing. - - det_bytes_per_sample = 2 * ( # At most 2 detector data copies. - 8 # 64 bit float / ints used - * (1 + 4) # detector timestream # pixel index and 3 IQU weights - + 1 # one byte per sample for flags - ) - - common_bytes_per_sample = ( - 8 * (4) # 64 bit floats # One quaternion per sample - + 1 # one byte per sample for common flag - ) - - group_nodes = 0 - group_mem = 0.0 - - # This just ensures we go through the loop once. - min_time_mem = 1.0 - - while group_mem < min_time_mem: - group_nodes += 1 - group_procs = group_nodes * procs_per_node - group_mem = group_nodes * bytes_per_node - - # NOTE: change this when moving to toast-3, since common data is in shared mem. - # So the prefactor should be nodes per group, not group_procs. - bytes_per_samp = ( - n_detector * det_bytes_per_sample + group_procs * common_bytes_per_sample - ) - # bytes_per_samp = ( - # n_detector * det_bytes_per_sample + group_nodes * common_bytes_per_sample - # ) - min_time_mem = min_time_samples * bytes_per_samp - if rank == 0: - log.verbose( - " Dist testing {} group nodes, {} proc/node, group mem = {}, comparing to minimum = {} ({} samp * {} bytes/samp)".format( - group_nodes, - procs_per_node, - group_mem, - min_time_mem, - min_time_samples, - bytes_per_samp, - ) - ) - - if rank == 0: - log.debug(" Dist selecting {} nodes per group".format(group_nodes)) - - # Now set the number of groups to get the target number of total samples. - - group_time_samples = min_time_samples - group_samples = n_detector * group_time_samples - - n_group = 1 + (total_samples // group_samples) - - time_samples = n_group * group_time_samples - - if rank == 0: - log.debug( - " Dist using {} groups, each with {} / {} (time / total) samples".format( - n_group, group_time_samples, group_samples - ) - ) - log.debug(" Dist using {} total samples".format(n_detector * time_samples)) - - return ( - n_detector, - time_samples, - group_procs, - group_nodes, - n_group, - group_time_samples, - ) - - -def job_size(mpicomm): - log = Logger.get() - - procs_per_node = 1 - node_rank = 0 - nodecomm = None - rank = 0 - procs = 1 - - if mpicomm is not None: - rank = mpicomm.rank - procs = mpicomm.size - nodecomm = mpicomm.Split_type(MPI.COMM_TYPE_SHARED, 0) - node_rank = nodecomm.rank - procs_per_node = nodecomm.size - min_per_node = mpicomm.allreduce(procs_per_node, op=MPI.MIN) - max_per_node = mpicomm.allreduce(procs_per_node, op=MPI.MAX) - if min_per_node != max_per_node: - raise RuntimeError("Nodes have inconsistent numbers of MPI ranks") - - # One process on each node gets available RAM and communicates it - avail = get_node_mem(mpicomm, node_rank) - - n_node = procs // procs_per_node - - if rank == 0: - log.info( - "Job running on {} nodes each with {} processes ({} total)".format( - n_node, procs_per_node, procs - ) - ) - return (procs_per_node, avail) - - -def job_config(mpicomm, cases): - env = Environment.get() - log = Logger.get() - - class args: - debug = False - # TOD Ground options - el_mod_step_deg = 0.0 - el_mod_rate_hz = 0.0 - el_mod_amplitude_deg = 1.0 - el_mod_sine = False - el_nod_deg = False - el_nod_every_scan = False - start_with_el_nod = False - end_with_el_nod = False - scan_rate = 1.0 - scan_rate_el = 0.0 - scan_accel = 1.0 - scan_accel_el = 0.0 - scan_cosecant_modulate = False - sun_angle_min = 30.0 - schedule = None # required - weather = "SIM" - timezone = 0 - sample_rate = 100.0 - coord = "C" - split_schedule = None - sort_schedule = False - hwp_rpm = 10.0 - hwp_step_deg = None - hwp_step_time_s = None - elevation_noise_a = 0.0 - elevation_noise_b = 0.0 - freq = "150" - do_daymaps = False - do_seasonmaps = False - # Pointing options - nside = 1024 - nside_submap = 16 - single_precision_pointing = False - common_flag_mask = 1 - # Polyfilter options - apply_polyfilter = False - poly_order = 0 - # Ground filter options - apply_groundfilter = False - ground_order = 0 - # Atmosphere options - simulate_atmosphere = False - simulate_coarse_atmosphere = False - focalplane_radius_deg = None - atm_verbosity = 0 - atm_lmin_center = 0.01 - atm_lmin_sigma = 0.001 - atm_lmax_center = 10.0 - atm_lmax_sigma = 10.0 - atm_gain = 2.0e-5 - atm_gain_coarse = 8.0e-5 - atm_zatm = 40000.0 - atm_zmax = 200.0 - atm_xstep = 10.0 - atm_ystep = 10.0 - atm_zstep = 10.0 - atm_nelem_sim_max = 10000 - atm_wind_dist = 3000.0 - atm_z0_center = 2000.0 - atm_z0_sigma = 0.0 - atm_T0_center = 280.0 - atm_T0_sigma = 10.0 - atm_cache = None - atm_apply_flags = False - # Noise simulation options - simulate_noise = False - # Gain scrambler - apply_gainscrambler = False - gain_sigma = 0.01 - # Map maker - mapmaker_prefix = "toast" - mapmaker_mask = None - mapmaker_weightmap = None - mapmaker_iter_max = 20 - mapmaker_precond_width = 100 - mapmaker_prefilter_order = None - mapmaker_baseline_length = 200.0 - mapmaker_noisefilter = False - mapmaker_fourier2D_order = None - mapmaker_fourier2D_subharmonics = None - write_hits = True - write_binmap = True - write_wcov = False - write_wcov_inv = False - zip_maps = False - # Monte Carlo - MC_start = 0 - MC_count = 1 - # Sky signal - input_map = None - simulate_sky = True - # Input dir - auxdir = "toast_inputs" - # Output - outdir = "toast" - tidas = None - spt3g = None - - parser = argparse.ArgumentParser( - description="Run a TOAST workflow scaled appropriately to the MPI communicator size and available memory.", - fromfile_prefix_chars="@", - ) - - parser.add_argument( - "--node_mem_gb", - required=False, - default=None, - type=float, - help="Use this much memory per node in GB", - ) - - parser.add_argument( - "--dry_run", - required=False, - default=None, - type=str, - help="Comma-separated total_procs,node_procs to simulate.", - ) - - parser.parse_args(namespace=args) - - procs = 1 - rank = 0 - if mpicomm is not None: - procs = mpicomm.size - rank = mpicomm.rank - - avail_node_bytes = None - procs_per_node = None - - if args.dry_run is not None: - dryrun_total, dryrun_node = args.dry_run.split(",") - dryrun_total = int(dryrun_total) - dryrun_node = int(dryrun_node) - if rank == 0: - log.info( - "DRY RUN simulating {} total processes with {} per node".format( - dryrun_total, dryrun_node - ) - ) - procs_per_node = dryrun_node - procs = dryrun_total - # We are simulating the distribution - avail_node_bytes = get_node_mem(mpicomm, 0) - - else: - # Get information about the actual job size - procs_per_node, avail_node_bytes = job_size(mpicomm) - - if rank == 0: - log.info( - "Minimum detected per-node memory available is {:0.2f} GB".format( - avail_node_bytes / (1024 ** 3) - ) - ) - - if args.node_mem_gb is not None: - avail_node_bytes = int((1024 ** 3) * args.node_mem_gb) - if rank == 0: - log.info( - "Setting per-node available memory to {:0.2f} GB as requested".format( - avail_node_bytes / (1024 ** 3) - ) - ) - - # Based on the total number of processes and count per node, choose the number of - # nodes in each observation and a focalplane such that every process has >= 4 - # detectors. - - n_nodes = procs // procs_per_node - if rank == 0: - log.info("Job has {} total nodes".format(n_nodes)) - - if rank == 0: - log.info("Examining {} possible cases to run:".format(len(cases))) - - selected_case = None - selected_nodes = None - n_detector = None - time_samples = None - group_procs = None - group_nodes = None - n_group = None - group_time_samples = None - - for case_name, case_samples in cases.items(): - ( - case_n_detector, - case_time_samples, - case_group_procs, - case_group_nodes, - case_n_group, - case_group_time_samples, - ) = sample_distribution( - rank, procs_per_node, avail_node_bytes, case_samples, args.sample_rate - ) - - case_min_nodes = case_n_group * case_group_nodes - if rank == 0: - log.info( - " {:8s}: requires {:d} nodes for {} MPI ranks and {:0.1f}GB per node".format( - case_name, - case_min_nodes, - procs_per_node, - avail_node_bytes / (1024 ** 3), - ) - ) - - if selected_nodes is None: - if case_min_nodes <= n_nodes: - # First case that fits in our job - selected_case = case_name - selected_nodes = case_min_nodes - n_detector = case_n_detector - time_samples = case_time_samples - group_procs = case_group_procs - group_nodes = case_group_nodes - n_group = case_n_group - group_time_samples = case_group_time_samples - else: - if (case_min_nodes <= n_nodes) and (case_min_nodes >= selected_nodes): - # This case fits in our job and is larger than the current one - selected_case = case_name - selected_nodes = case_min_nodes - n_detector = case_n_detector - time_samples = case_time_samples - group_procs = case_group_procs - group_nodes = case_group_nodes - n_group = case_n_group - group_time_samples = case_group_time_samples - - if selected_case is None: - msg = ( - "None of the available cases fit into aggregate memory. Use a larger job." - ) - if rank == 0: - log.error(msg) - raise RuntimeError(msg) - else: - if rank == 0: - log.info("Selected case '{}'".format(selected_case)) - - if rank == 0: - log.info("Using groups of {} nodes".format(group_nodes)) - - # Adjust number of groups - - if n_nodes % group_nodes != 0: - msg = "Current number of nodes ({}) is not divisible by the required group size ({})".format( - n_nodes, group_nodes - ) - if rank == 0: - log.error(msg) - raise RuntimeError(msg) - - n_group = n_nodes // group_nodes - group_time_samples = 1 + time_samples // n_group - - group_seconds = group_time_samples / args.sample_rate - - if args.simulate_atmosphere and args.weather is None: - raise RuntimeError("Cannot simulate atmosphere without a TOAST weather file") - - comm = None - if mpicomm is None or args.dry_run is not None: - comm = Comm(world=None) - else: - comm = Comm(world=mpicomm, groupsize=group_procs) - - jobdate = datetime.now().strftime("%Y%m%d-%H:%M:%S") - - args.outdir += "_{:06d}_grp-{:04d}p-{:02d}n_{}".format( - procs, group_procs, group_nodes, jobdate - ) - args.auxdir = os.path.join(args.outdir, "inputs") - - if rank == 0: - os.makedirs(args.outdir) - os.makedirs(args.auxdir, exist_ok=True) - - if rank == 0: - with open(os.path.join(args.outdir, "log"), "w") as f: - f.write("Running at {}\n".format(jobdate)) - f.write("TOAST version = {}\n".format(env.version())) - f.write("TOAST max threads = {}\n".format(env.max_threads())) - f.write("MPI Processes = {}\n".format(procs)) - f.write("MPI Processes per node = {}\n".format(procs_per_node)) - f.write( - "Memory per node = {:0.2f} GB\n".format(avail_node_bytes / (1024 ** 3)) - ) - f.write("Number of groups = {}\n".format(n_group)) - f.write("Group nodes = {}\n".format(group_nodes)) - f.write("Group MPI Processes = {}\n".format(group_procs)) - f.write("Case selected = {}\n".format(selected_case)) - f.write("Case number of detectors = {}\n".format(n_detector)) - f.write( - "Case total samples = {}\n".format( - n_group * group_time_samples * n_detector - ) - ) - f.write( - "Case samples per group = {}\n".format(group_time_samples * n_detector) - ) - f.write("Case data seconds per group = {}\n".format(group_seconds)) - f.write("Parameters:\n") - for k, v in vars(args).items(): - if re.match(r"_.*", k) is None: - f.write(" {} = {}\n".format(k, v)) - - args.schedule = os.path.join(args.auxdir, "schedule.txt") - args.input_map = os.path.join(args.auxdir, "cmb.fits") - - return args, comm, n_nodes, n_detector, selected_case, group_seconds, n_group - - -def create_schedules(args, max_ces_seconds, days): - opts = [ - "--site-lat", - str(-22.958064), - "--site-lon", - str(-67.786222), - "--site-alt", - str(5200.0), - "--site-name", - "ATACAMA", - "--telescope", - "atacama_telescope", - "--patch-coord", - "C", - "--el-min-deg", - str(30.0), - "--el-max-deg", - str(80.0), - "--sun-el-max-deg", - str(90.0), - "--sun-avoidance-angle-deg", - str(30.0), - "--moon-avoidance-angle-deg", - str(10.0), - "--start", - "2021-06-01 00:00:00", - "--gap-s", - str(600.0), - "--gap-small-s", - str(0.0), - "--fp-radius-deg", - str(0.0), - "--patch", - "BICEP,1,-10,-55,10,-58", - "--ces-max-time-s", - str(max_ces_seconds), - "--operational-days", - str(days), - ] - - if not os.path.isfile(args.schedule): - log = Logger.get() - log.info("Generating input schedule file {}:".format(args.schedule)) - - opts.extend(["--out", args.schedule]) - run_scheduler(opts=opts) - - -def create_input_maps(args): - if not os.path.isfile(args.input_map): - log = Logger.get() - log.info("Generating input map {}".format(args.input_map)) - - # This is *completely* fake- just to have something on the sky besides zeros. - - ell = np.arange(3 * args.nside - 1, dtype=np.float64) - - sig = 50.0 - numer = ell - 30.0 - tspec = (1.0 / (sig * np.sqrt(2.0 * np.pi))) * np.exp( - -0.5 * numer ** 2 / sig ** 2 - ) - tspec *= 2000.0 - - sig = 100.0 - numer = ell - 500.0 - espec = (1.0 / (sig * np.sqrt(2.0 * np.pi))) * np.exp( - -0.5 * numer ** 2 / sig ** 2 - ) - espec *= 1.0 - - cls = ( - tspec, - espec, - np.zeros(3 * args.nside - 1, dtype=np.float32), - np.zeros(3 * args.nside - 1, dtype=np.float32), - ) - maps = hp.synfast( - cls, - args.nside, - pol=True, - pixwin=False, - sigma=None, - new=True, - fwhm=np.radians(3.0 / 60.0), - verbose=False, - ) - # for m in maps: - # hp.reorder(m, inp="RING", out="NEST") - hp.write_map(args.input_map, maps, nest=True, fits_IDL=False, dtype=np.float32) - - import matplotlib.pyplot as plt - - hp.mollview(maps[0]) - plt.savefig("{}_fake-T.png".format(args.input_map)) - plt.close() - - hp.mollview(maps[1]) - plt.savefig("{}_fake-E.png".format(args.input_map)) - plt.close() - - -@function_timer -def create_focalplanes(args, comm, schedules, n_detector): - """Attach a focalplane to each of the schedules. - - Args: - schedules (list) : List of Schedule instances. - Each schedule has two members, telescope - and ceslist, a list of CES objects. - Returns: - detweights (dict) : Inverse variance noise weights for every - detector across all focal planes. In [K_CMB^-2]. - They can be used to bin the TOD. - """ - - # Load focalplane information - - focalplanes = [] - if comm.world_rank == 0: - # First create a fake hexagonal focalplane - n_pixel = 1 - ring = 1 - while 2 * n_pixel < n_detector: - n_pixel += 6 * ring - ring += 1 - - fake = fake_hexagon_focalplane( - n_pix=n_pixel, - width_deg=10.0, - samplerate=100.0, - epsilon=0.0, - net=10.0, - fmin=0.0, - alpha=1.0, - fknee=0.05, - ) - - # Now truncate the detectors to the desired count. - newdat = dict() - off = 0 - for k, v in fake.detector_data.items(): - newdat[k] = v - off += 1 - if off >= n_detector: - break - fake.detector_data = newdat - fake.reset_properties() - focalplanes.append(fake) - - if comm.comm_world is not None: - focalplanes = comm.comm_world.bcast(focalplanes) - - if len(focalplanes) == 1 and len(schedules) > 1: - focalplanes *= len(schedules) - - # Append a focal plane and telescope to each entry in the schedules - # list and assemble a detector weight dictionary that represents all - # detectors in all focalplanes - detweights = {} - for schedule, focalplane in zip(schedules, focalplanes): - schedule.telescope.focalplane = focalplane - detweights.update(schedule.telescope.focalplane.detweights) - - return detweights - - -@function_timer -def create_observation(args, comm, telescope, ces, verbose=True): - """Create a TOAST observation. - - Create an observation for the CES scan - - Args: - args : argparse arguments - comm : TOAST communicator - ces (CES) : One constant elevation scan - - """ - focalplane = telescope.focalplane - site = telescope.site - weather = site.weather - noise = focalplane.noise - totsamples = int((ces.stop_time - ces.start_time) * args.sample_rate) - - # create the TOD for this observation - - if comm.comm_group is not None: - ndetrank = comm.comm_group.size - else: - ndetrank = 1 - - if args.el_nod_deg and (ces.subscan == 0 or args.el_nod_every_scan): - el_nod = args.el_nod_deg - else: - el_nod = None - - try: - tod = TODGround( - comm.comm_group, - focalplane.detquats, - totsamples, - detranks=ndetrank, - boresight_angle=ces.boresight_angle, - firsttime=ces.start_time, - rate=args.sample_rate, - site_lon=site.lon, - site_lat=site.lat, - site_alt=site.alt, - azmin=ces.azmin, - azmax=ces.azmax, - el=ces.el, - el_nod=el_nod, - start_with_elnod=args.start_with_el_nod, - end_with_elnod=args.end_with_el_nod, - el_mod_step=args.el_mod_step_deg, - el_mod_rate=args.el_mod_rate_hz, - el_mod_amplitude=args.el_mod_amplitude_deg, - el_mod_sine=args.el_mod_sine, - scanrate=args.scan_rate, - scanrate_el=args.scan_rate_el, - scan_accel=args.scan_accel, - scan_accel_el=args.scan_accel_el, - cosecant_modulation=args.scan_cosecant_modulate, - CES_start=None, - CES_stop=None, - sun_angle_min=args.sun_angle_min, - coord=args.coord, - sampsizes=None, - report_timing=args.debug, - hwprpm=args.hwp_rpm, - hwpstep=args.hwp_step_deg, - hwpsteptime=args.hwp_step_time_s, - ) - except RuntimeError as e: - raise RuntimeError( - 'Failed to create TOD for {}-{}-{}: "{}"' - "".format(ces.name, ces.scan, ces.subscan, e) - ) - - # Create the observation - - obs = {} - obs["name"] = "CES-{}-{}-{}-{}-{}".format( - site.name, telescope.name, ces.name, ces.scan, ces.subscan - ) - obs["tod"] = tod - obs["baselines"] = None - obs["noise"] = copy.deepcopy(noise) - obs["id"] = int(ces.mjdstart * 10000) - obs["intervals"] = tod.subscans - obs["site"] = site - obs["site_name"] = site.name - obs["site_id"] = site.id - obs["altitude"] = site.alt - obs["weather"] = site.weather - obs["telescope"] = telescope - obs["telescope_name"] = telescope.name - obs["telescope_id"] = telescope.id - obs["focalplane"] = telescope.focalplane.detector_data - obs["fpradius"] = telescope.focalplane.radius - obs["start_time"] = ces.start_time - obs["season"] = ces.season - obs["date"] = ces.start_date - obs["MJD"] = ces.mjdstart - obs["rising"] = ces.rising - obs["mindist_sun"] = ces.mindist_sun - obs["mindist_moon"] = ces.mindist_moon - obs["el_sun"] = ces.el_sun - return obs - - -@function_timer -def create_observations(args, comm, schedules): - """Create and distribute TOAST observations for every CES in - schedules. - - Args: - schedules (iterable) : a list of Schedule objects. - """ - log = Logger.get() - timer = Timer() - timer.start() - - data = Data(comm) - - # Loop over the schedules, distributing each schedule evenly across - # the process groups. For now, we'll assume that each schedule has - # the same number of operational days and the number of process groups - # matches the number of operational days. Relaxing these constraints - # will cause the season break to occur on different process groups - # for different schedules and prevent splitting the communicator. - - total_samples = 0 - group_samples = 0 - for schedule in schedules: - - telescope = schedule.telescope - all_ces = schedule.ceslist - nces = len(all_ces) - - breaks = pipeline_tools.get_breaks(comm, all_ces, args) - - ces_weights = [x.stop_time - x.start_time for x in all_ces] - groupdist = distribute_discrete(ces_weights, comm.ngroups, breaks=breaks) - - # groupdist = distribute_uniform(nces, comm.ngroups, breaks=breaks) - group_firstobs = groupdist[comm.group][0] - group_numobs = groupdist[comm.group][1] - - for ices in range(group_firstobs, group_firstobs + group_numobs): - obs = create_observation(args, comm, telescope, all_ces[ices]) - group_samples += obs["tod"].total_samples - data.obs.append(obs) - - if comm.comm_rank is not None: - if comm.comm_group.rank == 0: - total_samples = comm.comm_rank.allreduce(group_samples, op=MPI.SUM) - total_samples = comm.comm_group.bcast(total_samples, root=0) - if comm.comm_world is None or comm.comm_group.rank == 0: - log.info("Group # {:4} has {} observations.".format(comm.group, len(data.obs))) - - if len(data.obs) == 0: - raise RuntimeError( - "Too many tasks. Every MPI task must " - "be assigned to at least one observation." - ) - - if comm.comm_world is not None: - comm.comm_world.barrier() - timer.stop() - if comm.world_rank == 0: - timer.report("Simulated scans") - - # Split the data object for each telescope for separate mapmaking. - # We could also split by site. - - if len(schedules) > 1: - telescope_data = data.split("telescope_name") - if len(telescope_data) == 1: - # Only one telescope available - telescope_data = [] - else: - telescope_data = [] - telescope_data.insert(0, ("all", data)) - return data, telescope_data, total_samples - - -def setup_sigcopy(args): - """Determine if an extra copy of the atmospheric signal is needed. - - When we simulate multichroic focal planes, the frequency-independent - part of the atmospheric noise is simulated first and then the - frequency scaling is applied to a copy of the atmospheric noise. - """ - if len(args.freq.split(",")) == 1: - totalname = "total" - totalname_freq = "total" - else: - totalname = "total" - totalname_freq = "total_freq" - - return totalname, totalname_freq - - -@function_timer -def setup_output(args, comm, mc, freq): - outpath = "{}/{:03}/{:03}".format(args.outdir, mc, int(freq)) - if comm.world_rank == 0: - os.makedirs(outpath, exist_ok=True) - return outpath - - -def main(): - env = Environment.get() - env.enable_function_timers() - - log = Logger.get() - gt = GlobalTimers.get() - gt.start("toast_benchmark (total)") - - mpiworld, procs, rank = get_world() - - if rank == 0: - log.info("TOAST version = {}".format(env.version())) - log.info("Using a maximum of {} threads per process".format(env.max_threads())) - if mpiworld is None: - log.info("Running serially with one process at {}".format(str(datetime.now()))) - else: - if rank == 0: - log.info( - "Running with {} processes at {}".format(procs, str(datetime.now())) - ) - - cases = { - "tiny": 5000000, # O(1) GB RAM - "xsmall": 50000000, # O(10) GB RAM - "small": 500000000, # O(100) GB RAM - "medium": 5000000000, # O(1) TB RAM - "large": 50000000000, # O(10) TB RAM - "xlarge": 500000000000, # O(100) TB RAM - "heroic": 5000000000000, # O(1000) TB RAM - } - - args, comm, n_nodes, n_detector, case, group_seconds, n_group = job_config( - mpiworld, cases - ) - - # Note: The number of "days" here will just be an approximation of the desired - # data volume since we are doing a realistic schedule for a real observing site. - - n_days = int(2.0 * (group_seconds * n_group) / (24 * 3600)) - if n_days == 0: - n_days = 1 - - if rank == 0: - log.info( - "Using {} detectors for approximately {} days".format(n_detector, n_days) - ) - - # Create the schedule file and input maps on one process - if rank == 0: - create_schedules(args, group_seconds, n_days) - create_input_maps(args) - if mpiworld is not None: - mpiworld.barrier() - - if args.dry_run is not None: - if rank == 0: - log.info("Exit from dry run") - # We are done! - sys.exit(0) - - gt.start("toast_benchmark (science work)") - - # Load and broadcast the schedule file - - schedules = pipeline_tools.load_schedule(args, comm) - - # Load the weather and append to schedules - - pipeline_tools.load_weather(args, comm, schedules) - - # Simulate the focalplane - - detweights = create_focalplanes(args, comm, schedules, n_detector) - - # Create the TOAST data object to match the schedule. This will - # include simulating the boresight pointing. - - data, telescope_data, total_samples = create_observations(args, comm, schedules) - - # handle = None - # if comm.world_rank == 0: - # handle = open(os.path.join(args.outdir, "distdata.txt"), "w") - # data.info(handle) - # if comm.world_rank == 0: - # handle.close() - # if comm.comm_world is not None: - # comm.comm_world.barrier() - - # Split the communicator for day and season mapmaking - - time_comms = pipeline_tools.get_time_communicators(args, comm, data) - - # Expand boresight quaternions into detector pointing weights and - # pixel numbers - - pipeline_tools.expand_pointing(args, comm, data) - - # Optionally rewrite the noise PSD:s in each observation to include - # elevation-dependence - - pipeline_tools.get_elevation_noise(args, comm, data) - - # Purge the pointing if we are NOT going to export the - # data to a TIDAS volume - if (args.tidas is None) and (args.spt3g is None): - for ob in data.obs: - tod = ob["tod"] - tod.free_radec_quats() - - # Prepare auxiliary information for distributed map objects - - signalname = pipeline_tools.scan_sky_signal(args, comm, data, "signal") - - # Set up objects to take copies of the TOD at appropriate times - - totalname, totalname_freq = setup_sigcopy(args) - - # Loop over Monte Carlos - - firstmc = args.MC_start - nsimu = args.MC_count - - freqs = [float(freq) for freq in args.freq.split(",")] - nfreq = len(freqs) - - for mc in range(firstmc, firstmc + nsimu): - - pipeline_tools.simulate_atmosphere(args, comm, data, mc, totalname) - - # Loop over frequencies with identical focal planes and identical - # atmospheric noise. - - for ifreq, freq in enumerate(freqs): - - if comm.world_rank == 0: - log.info( - "Processing frequency {}GHz {} / {}, MC = {}".format( - freq, ifreq + 1, nfreq, mc - ) - ) - - # Make a copy of the atmosphere so we can scramble the gains and apply - # frequency-dependent scaling. - pipeline_tools.copy_signal(args, comm, data, totalname, totalname_freq) - - pipeline_tools.scale_atmosphere_by_frequency( - args, comm, data, freq=freq, mc=mc, cache_name=totalname_freq - ) - - pipeline_tools.update_atmospheric_noise_weights(args, comm, data, freq, mc) - - # Add previously simulated sky signal to the atmospheric noise. - - pipeline_tools.add_signal( - args, comm, data, totalname_freq, signalname, purge=(nsimu == 1) - ) - - mcoffset = ifreq * 1000000 - - pipeline_tools.simulate_noise( - args, comm, data, mc + mcoffset, totalname_freq - ) - - pipeline_tools.scramble_gains( - args, comm, data, mc + mcoffset, totalname_freq - ) - - outpath = setup_output(args, comm, mc + mcoffset, freq) - - # Bin and destripe maps - - pipeline_tools.apply_mapmaker( - args, - comm, - data, - outpath, - totalname_freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=(mc == firstmc), - ) - - if args.apply_polyfilter or args.apply_groundfilter: - - # Filter signal - - pipeline_tools.apply_polyfilter(args, comm, data, totalname_freq) - - pipeline_tools.apply_groundfilter(args, comm, data, totalname_freq) - - # Bin filtered maps - - pipeline_tools.apply_mapmaker( - args, - comm, - data, - outpath, - totalname_freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=False, - extra_prefix="filtered", - bin_only=True, - ) - - gt.stop_all() - if mpiworld is not None: - mpiworld.barrier() - - runtime = gt.seconds("toast_benchmark (science work)") - prefactor = 1.0e-3 - kilo_samples = 1.0e-3 * total_samples - sample_factor = 1.2 - det_factor = 2.0 - metric = ( - prefactor - * n_detector ** det_factor - * kilo_samples ** sample_factor - / (n_nodes * runtime) - ) - if rank == 0: - msg = "Science Metric: {:0.1e} * ({:d}**{:0.2f}) * ({:0.3e}**{:0.3f}) / ({:0.1f} * {}) = {:0.2f}".format( - prefactor, - n_detector, - det_factor, - kilo_samples, - sample_factor, - runtime, - n_nodes, - metric, - ) - log.info("") - log.info(msg) - log.info("") - with open(os.path.join(args.outdir, "log"), "a") as f: - f.write(msg) - f.write("\n\n") - - timer = Timer() - timer.start() - alltimers = gather_timers(comm=mpiworld) - if comm.world_rank == 0: - out = os.path.join(args.outdir, "timing") - dump_timing(alltimers, out) - with open(os.path.join(args.outdir, "log"), "a") as f: - f.write("Copy of Global Timers:\n") - with open("{}.csv".format(out), "r") as t: - f.write(t.read()) - timer.stop() - timer.report("Gather and dump timing info") - return - - -if __name__ == "__main__": - try: - main() - except Exception: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - if procs == 1: - raise - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_cache_test.py b/pipelines/toast_cache_test.py deleted file mode 100644 index 9d62ae3a1..000000000 --- a/pipelines/toast_cache_test.py +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -"""Test the ability to free memory from a toast.Cache. - -This stores the following objects per detector in a Cache: - -- Detector signal as float64 -- Detector flags as uint8 -- Detector pointing pixel numbers as int64 -- Detector pointing weights as float32 - -It reports the memory available before and after this allocation. -Then it frees the buffers of a given type from all detectors and -compares the resulting change to what is expected. - -""" -import os -import re -import sys -import argparse -import traceback -import psutil - -import numpy as np - -from toast.utils import Logger - -from toast.cache import Cache - - -def main(): - log = Logger.get() - - parser = argparse.ArgumentParser(description="Allocate and free cache objects.") - - parser.add_argument( - "--ndet", required=False, type=int, default=10, help="The number of detectors" - ) - - parser.add_argument( - "--nobs", required=False, type=int, default=2, help="The number of observations" - ) - - parser.add_argument( - "--obsminutes", - required=False, - type=int, - default=60, - help="The number of minutes in each observation.", - ) - - parser.add_argument( - "--rate", required=False, type=float, default=37.0, help="The sample rate." - ) - - parser.add_argument( - "--nloop", - required=False, - type=int, - default=2, - help="The number of allocate / free loops", - ) - - args = parser.parse_args() - - log.info("Input parameters:") - log.info(" {} observations".format(args.nobs)) - log.info(" {} minutes per obs".format(args.obsminutes)) - log.info(" {} detectors per obs".format(args.ndet)) - log.info(" {}Hz sample rate".format(args.rate)) - - nsampobs = int(args.obsminutes * 60 * args.rate) - - nsamptot = args.ndet * args.nobs * nsampobs - - log.info("{} total samples across all detectors and observations".format(nsamptot)) - - bytes_sigobs = nsampobs * 8 - bytes_sigtot = nsamptot * 8 - bytes_flagobs = nsampobs * 1 - bytes_flagtot = nsamptot * 1 - bytes_pixobs = nsampobs * 8 - bytes_pixtot = nsamptot * 8 - bytes_wtobs = 3 * nsampobs * 4 - bytes_wttot = 3 * nsamptot * 4 - - bytes_tot = bytes_sigtot + bytes_flagtot + bytes_pixtot + bytes_wttot - bytes_tot_mb = bytes_tot / 2 ** 20 - log.info( - "{} total bytes ({:0.2f}MB) of data expected".format(bytes_tot, bytes_tot_mb) - ) - - for lp in range(args.nloop): - log.info("Allocation loop {:02d}".format(lp)) - vmem = psutil.virtual_memory()._asdict() - avstart = vmem["available"] - avstart_mb = avstart / 2 ** 20 - log.info(" Starting with {:0.2f}MB of available memory".format(avstart_mb)) - - # The list of Caches, one per "observation" - caches = list() - - # This structure holds external references to cache objects, to ensure that we - # can destroy objects and free memory, even if external references are held. - refs = list() - - for ob in range(args.nobs): - ch = Cache() - rf = dict() - for det in range(args.ndet): - dname = "{:04d}".format(det) - cname = "{}_sig".format(dname) - rf[cname] = ch.create(cname, np.float64, (nsampobs,)) - cname = "{}_flg".format(dname) - rf[cname] = ch.create(cname, np.uint8, (nsampobs,)) - cname = "{}_pix".format(dname) - rf[cname] = ch.create(cname, np.int64, (nsampobs,)) - cname = "{}_wgt".format(dname) - rf[cname] = ch.create(cname, np.float32, (nsampobs, 3)) - caches.append(ch) - refs.append(rf) - - vmem = psutil.virtual_memory()._asdict() - avpost = vmem["available"] - avpost_mb = avpost / 2 ** 20 - log.info(" After allocation, {:0.2f}MB of available memory".format(avpost_mb)) - - diff = avstart_mb - avpost_mb - diffperc = 100.0 * np.absolute(diff - bytes_tot_mb) / bytes_tot_mb - log.info( - " Difference is {:0.2f}MB, expected {:0.2f}MB ({:0.2f}% residual)".format( - diff, bytes_tot_mb, diffperc - ) - ) - - for suf in ["wgt", "pix", "flg", "sig"]: - for ob, ch in zip(range(args.nobs), caches): - for det in range(args.ndet): - dname = "{:04d}".format(det) - ch.destroy("{}_{}".format(dname, suf)) - - vmem = psutil.virtual_memory()._asdict() - avfinal = vmem["available"] - avfinal_mb = avfinal / 2 ** 20 - log.info( - " After destruction, {:0.2f}MB of available memory".format(avfinal_mb) - ) - - diff = avfinal_mb - avpost_mb - diffperc = 100.0 * np.absolute(diff - bytes_tot_mb) / bytes_tot_mb - log.info( - " Difference is {:0.2f}MB, expected {:0.2f}MB ({:0.2f}% residual)".format( - diff, bytes_tot_mb, diffperc - ) - ) - - return - - -if __name__ == "__main__": - try: - main() - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - print("".join(lines), flush=True) diff --git a/pipelines/toast_cov_invert.py b/pipelines/toast_cov_invert.py deleted file mode 100644 index a8a61b8ff..000000000 --- a/pipelines/toast_cov_invert.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -"""Invert a block diagonal covariance matrix. -""" -import os -import re -import sys -import argparse -import traceback - -import numpy as np - -import healpy as hp - -from toast.mpi import get_world - -from toast.utils import Logger - -from toast.dist import distribute_uniform - -from toast.map import DistPixels, covariance_invert - - -def main(): - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Read a toast covariance matrix and invert it." - ) - - parser.add_argument( - "--input", required=True, default=None, help="The input covariance FITS file" - ) - - parser.add_argument( - "--output", - required=False, - default=None, - help="The output inverse covariance FITS file.", - ) - - parser.add_argument( - "--rcond", - required=False, - default=None, - help="Optionally write the inverse condition number map to this file.", - ) - - parser.add_argument( - "--single", - required=False, - default=False, - action="store_true", - help="Write the output in single precision.", - ) - - parser.add_argument( - "--threshold", - required=False, - default=1e-3, - type=np.float, - help="Reciprocal condition number threshold", - ) - - try: - args = parser.parse_args() - except SystemExit: - return - - # get options - - infile = args.input - outfile = None - if args.output is not None: - outfile = args.output - else: - inmat = re.match(r"(.*)\.fits", infile) - if inmat is None: - log.error("input file should have .fits extension") - return - inroot = inmat.group(1) - outfile = "{}_inv.fits".format(inroot) - - # Get the default communicator - mpiworld, procs, rank = get_world() - - # We need to read the header to get the size of the matrix. - # This would be a trivial function call in astropy.fits or - # fitsio, but we don't want to bring in a whole new dependency - # just for that. Instead, we open the file with healpy in memmap - # mode so that nothing is actually read except the header. - - nside = 0 - ncovnz = 0 - if rank == 0: - fake, head = hp.read_map(infile, h=True, memmap=True) - for key, val in head: - if key == "NSIDE": - nside = int(val) - if key == "TFIELDS": - ncovnz = int(val) - if mpiworld is not None: - nside = mpiworld.bcast(nside, root=0) - ncovnz = mpiworld.bcast(ncovnz, root=0) - - nnz = int(((np.sqrt(8.0 * ncovnz) - 1.0) / 2.0) + 0.5) - - npix = 12 * nside ** 2 - subnside = int(nside / 16) - if subnside == 0: - subnside = 1 - subnpix = 12 * subnside ** 2 - nsubmap = int(npix / subnpix) - - # divide the submaps as evenly as possible among processes - - dist = distribute_uniform(nsubmap, procs) - local = np.arange(dist[rank][0], dist[rank][0] + dist[rank][1]) - - if rank == 0: - if os.path.isfile(outfile): - os.remove(outfile) - - if mpiworld is not None: - mpiworld.barrier() - - # create the covariance and inverse condition number map - - cov = None - invcov = None - rcond = None - - cov = DistPixels( - comm=mpiworld, - dtype=np.float64, - size=npix, - nnz=ncovnz, - submap=subnpix, - local=local, - ) - - if args.single: - invcov = DistPixels( - comm=mpiworld, - dtype=np.float32, - size=npix, - nnz=ncovnz, - submap=subnpix, - local=local, - ) - else: - invcov = cov - - if args.rcond is not None: - rcond = DistPixels( - comm=mpiworld, - dtype=np.float64, - size=npix, - nnz=nnz, - submap=subnpix, - local=local, - ) - - # read the covariance - if rank == 0: - log.info("Reading covariance from {}".format(infile)) - cov.read_healpix_fits(infile) - - # every process computes its local piece - if rank == 0: - log.info("Inverting covariance") - covariance_invert(cov, args.threshold, rcond=rcond) - - if args.single: - invcov.data[:] = cov.data.astype(np.float32) - - # write the inverted covariance - if rank == 0: - log.info("Writing inverted covariance to {}".format(outfile)) - invcov.write_healpix_fits(outfile) - - # write the condition number - - if args.rcond is not None: - if rank == 0: - log.info("Writing condition number map") - rcond.write_healpix_fits(args.rcond) - - return - - -if __name__ == "__main__": - try: - main() - except: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_cov_rcond.py b/pipelines/toast_cov_rcond.py deleted file mode 100644 index eb1108506..000000000 --- a/pipelines/toast_cov_rcond.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -"""Invert a block diagonal covariance matrix. -""" -import os -import re -import sys -import argparse -import traceback - -import numpy as np - -import healpy as hp - -from toast.mpi import get_world - -from toast.utils import Logger - -from toast.dist import distribute_uniform - -from toast.map import DistPixels, covariance_rcond - - -def main(): - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Read a toast covariance matrix and write the inverse condition number map" - ) - - parser.add_argument( - "--input", required=True, default=None, help="The input covariance FITS file" - ) - - parser.add_argument( - "--output", - required=False, - default=None, - help="The output inverse condition map FITS file.", - ) - - try: - args = parser.parse_args() - except SystemExit: - return - - # get options - - infile = args.input - outfile = None - if args.output is not None: - outfile = args.output - else: - inmat = re.match(r"(.*)\.fits", infile) - if inmat is None: - log.error("input file should have .fits extension") - return - inroot = inmat.group(1) - outfile = "{}_rcond.fits".format(inroot) - - # Get the default communicator - mpiworld, procs, rank = get_world() - - # We need to read the header to get the size of the matrix. - # This would be a trivial function call in astropy.fits or - # fitsio, but we don't want to bring in a whole new dependency - # just for that. Instead, we open the file with healpy in memmap - # mode so that nothing is actually read except the header. - - nside = 0 - nnz = 0 - if rank == 0: - fake, head = hp.read_map(infile, h=True, memmap=True) - for key, val in head: - if key == "NSIDE": - nside = int(val) - if key == "TFIELDS": - nnz = int(val) - if mpiworld is not None: - nside = mpiworld.bcast(nside, root=0) - nnz = mpiworld.bcast(nnz, root=0) - - npix = 12 * nside ** 2 - subnside = int(nside / 16) - if subnside == 0: - subnside = 1 - subnpix = 12 * subnside ** 2 - nsubmap = int(npix / subnpix) - - # divide the submaps as evenly as possible among processes - - dist = distribute_uniform(nsubmap, procs) - local = np.arange(dist[rank][0], dist[rank][0] + dist[rank][1]) - - if rank == 0: - if os.path.isfile(outfile): - os.remove(outfile) - - if mpiworld is not None: - mpiworld.barrier() - - # create the covariance and inverse condition number map - - cov = DistPixels( - comm=mpiworld, dtype=np.float64, size=npix, nnz=nnz, submap=subnpix, local=local - ) - - # read the covariance - log.info("Reading covariance {}".format(infile)) - cov.read_healpix_fits(infile) - - # every process computes its local piece - log.info("Computing condition number map") - rcond = covariance_rcond(cov) - - # write the map - log.info("Writing condition number map") - rcond.write_healpix_fits(outfile) - return - - -if __name__ == "__main__": - try: - main() - except: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_env_test.py b/pipelines/toast_env_test.py deleted file mode 100644 index f34843172..000000000 --- a/pipelines/toast_env_test.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -"""This does some simple tests of the TOAST runtime environment. -""" - -import sys -import argparse -import traceback - -from toast.mpi import get_world, Comm - -from toast.utils import Logger, Environment, numba_threading_layer - - -def main(): - env = Environment.get() - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Test the TOAST runtime environment.", fromfile_prefix_chars="@" - ) - - parser.add_argument( - "--groupsize", - required=False, - type=int, - default=0, - help="size of processor groups used to distribute observations", - ) - - try: - args = parser.parse_args() - except SystemExit: - return - - mpiworld, procs, rank = get_world() - if rank == 0: - print(env) - log.info("Numba threading layer set to '{}'".format(numba_threading_layer)) - if mpiworld is None: - log.info("Running serially with one process") - else: - if rank == 0: - log.info("Running with {} processes".format(procs)) - - groupsize = args.groupsize - if groupsize <= 0: - groupsize = procs - - if rank == 0: - log.info("Using group size of {} processes".format(groupsize)) - - comm = Comm(world=mpiworld, groupsize=groupsize) - - log.info( - "Process {}: world rank {}, group {} of {}, group rank {}".format( - rank, comm.world_rank, comm.group + 1, comm.ngroups, comm.group_rank - ) - ) - - return - - -if __name__ == "__main__": - try: - main() - except: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_fake_focalplane.py b/pipelines/toast_fake_focalplane.py deleted file mode 100644 index cbdb5d25a..000000000 --- a/pipelines/toast_fake_focalplane.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -"""Generate a focalplane pickle file compatible with the example scripts. -""" - -import sys -import argparse -import traceback - -import pickle - -import numpy as np - -from scipy.constants import degree - -from toast.mpi import get_world - -from toast.utils import Logger - -from toast.tod import hex_pol_angles_qu, hex_layout, plot_focalplane - - -def main(): - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Simulate fake hexagonal focalplane.", fromfile_prefix_chars="@" - ) - - parser.add_argument( - "--minpix", - required=False, - type=int, - default=100, - help="minimum number of pixels to use", - ) - - parser.add_argument( - "--out", - required=False, - default="fp_fake", - help="Root name of output pickle file", - ) - - parser.add_argument( - "--fwhm", required=False, type=float, default=5.0, help="beam FWHM in arcmin" - ) - - parser.add_argument( - "--fwhm_sigma", - required=False, - type=float, - default=0, - help="Relative beam FWHM distribution width", - ) - - parser.add_argument( - "--fov", - required=False, - type=float, - default=5.0, - help="Field of View in degrees", - ) - - parser.add_argument( - "--psd_fknee", - required=False, - type=float, - default=0.05, - help="Detector noise model f_knee in Hz", - ) - - parser.add_argument( - "--psd_NET", - required=False, - type=float, - default=60.0e-6, - help="Detector noise model NET in K*sqrt(sec)", - ) - - parser.add_argument( - "--psd_alpha", - required=False, - type=float, - default=1.0, - help="Detector noise model slope", - ) - - parser.add_argument( - "--psd_fmin", - required=False, - type=float, - default=1.0e-5, - help="Detector noise model f_min in Hz", - ) - - parser.add_argument( - "--bandcenter_ghz", - required=False, - type=float, - help="Band center frequency [GHz]", - ) - - parser.add_argument( - "--bandcenter_sigma", - required=False, - type=float, - default=0, - help="Relative band center distribution width", - ) - - parser.add_argument( - "--bandwidth_ghz", required=False, type=float, help="Bandwidth [GHz]" - ) - - parser.add_argument( - "--bandwidth_sigma", - required=False, - type=float, - default=0, - help="Relative bandwidth distribution width", - ) - - parser.add_argument( - "--random_seed", - required=False, - type=np.int, - default=123456, - help="Random number generator seed for randomized " "detector parameters", - ) - - try: - args = parser.parse_args() - except SystemExit: - return - - # Get the default communicator - mpiworld, procs, rank = get_world() - - # Guard against being called with multiple processes - if rank == 0: - # Make one big hexagon layout at the center of the focalplane. - # Compute the number of pixels that is at least the number requested. - - test = args.minpix - 1 - nrings = 0 - while (test - 6 * nrings) > 0: - test -= 6 * nrings - nrings += 1 - - npix = 1 - for r in range(1, nrings + 1): - npix += 6 * r - - log.info("using {} pixels ({} detectors)".format(npix, npix * 2)) - - # Translate the field-of-view into distance between flag sides - angwidth = args.fov * np.cos(30 * degree) - - Apol = hex_pol_angles_qu(npix, offset=0.0) - Bpol = hex_pol_angles_qu(npix, offset=90.0) - - Adets = hex_layout(npix, angwidth, "fake_", "A", Apol) - Bdets = hex_layout(npix, angwidth, "fake_", "B", Bpol) - - dets = Adets.copy() - dets.update(Bdets) - - np.random.seed(args.random_seed) - - for indx, d in enumerate(sorted(dets.keys())): - dets[d]["fknee"] = args.psd_fknee - dets[d]["fmin"] = args.psd_fmin - dets[d]["alpha"] = args.psd_alpha - dets[d]["NET"] = args.psd_NET - # This is in degrees, but the input is in arcmin. - dets[d]["fwhm_deg"] = (args.fwhm / 60.0) * ( - 1 + np.random.randn() * args.fwhm_sigma - ) - # This is a fixed value, in arcmin. - dets[d]["fwhm"] = args.fwhm - if args.bandcenter_ghz: - dets[d]["bandcenter_ghz"] = args.bandcenter_ghz * ( - 1 + np.random.randn() * args.bandcenter_sigma - ) - if args.bandwidth_ghz: - dets[d]["bandwidth_ghz"] = args.bandwidth_ghz * ( - 1 + np.random.randn() * args.bandwidth_sigma - ) - dets[d]["index"] = indx - - outfile = "{}_{}".format(args.out, npix) - qdets = {x: y["quat"] for x, y in dets.items()} - beams = {x: (60.0 * y["fwhm_deg"]) for x, y in dets.items()} - plot_focalplane(qdets, args.fov, args.fov, "{}.png".format(outfile), fwhm=beams) - - with open("{}.pkl".format(outfile), "wb") as p: - pickle.dump(dets, p) - - return - - -if __name__ == "__main__": - try: - main() - except: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_ground_schedule.py b/pipelines/toast_ground_schedule.py deleted file mode 100644 index 41aced87d..000000000 --- a/pipelines/toast_ground_schedule.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -""" -This script creates a CES schedule file that can be used as input -to toast_ground_sim.py -""" - -import sys -import traceback - -from toast.mpi import get_world -from toast.timing import GlobalTimers -from toast.schedule import run_scheduler - - -def main(): - gt = GlobalTimers.get() - gt.start("toast_ground_schedule") - - run_scheduler() - - gt.stop_all() - gt.report() - return - - -if __name__ == "__main__": - try: - main() - except Exception as e: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None and procs > 1: - mpiworld.Abort(6) - else: - raise e diff --git a/pipelines/toast_ground_sim.py b/pipelines/toast_ground_sim.py deleted file mode 100644 index 35ce4ef17..000000000 --- a/pipelines/toast_ground_sim.py +++ /dev/null @@ -1,643 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -""" -This script runs a ground simulation and makes a map. -""" - - -import os - -if "TOAST_STARTUP_DELAY" in os.environ: - import numpy as np - import time - - delay = np.float(os.environ["TOAST_STARTUP_DELAY"]) - wait = np.random.rand() * delay - # print('Sleeping for {} seconds before importing TOAST'.format(wait), - # flush=True) - time.sleep(wait) - -import copy -import sys -import argparse -import traceback -import pickle - -import numpy as np - -from toast.mpi import get_world, Comm - -from toast.dist import distribute_uniform, Data - -from toast.utils import Logger, Environment, memreport - -from toast.timing import function_timer, GlobalTimers, Timer, gather_timers -from toast.timing import dump as dump_timing - -from toast.todmap import TODGround - -from toast import pipeline_tools - -# import warnings -# warnings.filterwarnings('error') -# warnings.simplefilter('ignore', ImportWarning) -# warnings.simplefilter('ignore', ResourceWarning) -# warnings.simplefilter('ignore', DeprecationWarning) -# warnings.filterwarnings("ignore", message="numpy.dtype size changed") -# warnings.filterwarnings("ignore", message="numpy.ufunc size changed") - - -def parse_arguments(comm): - timer = Timer() - timer.start() - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Simulate ground-based boresight pointing. Simulate " - "atmosphere and make maps for some number of noise Monte Carlos.", - fromfile_prefix_chars="@", - ) - - pipeline_tools.add_dist_args(parser) - pipeline_tools.add_debug_args(parser) - pipeline_tools.add_todground_args(parser) - pipeline_tools.add_pointing_args(parser) - pipeline_tools.add_polyfilter_args(parser) - pipeline_tools.add_polyfilter2D_args(parser) - pipeline_tools.add_groundfilter_args(parser) - pipeline_tools.add_atmosphere_args(parser) - pipeline_tools.add_noise_args(parser) - pipeline_tools.add_gainscrambler_args(parser) - pipeline_tools.add_madam_args(parser) - pipeline_tools.add_mapmaker_args(parser) - pipeline_tools.add_sky_map_args(parser) - pipeline_tools.add_pysm_args(parser) - pipeline_tools.add_sss_args(parser) - pipeline_tools.add_tidas_args(parser) - pipeline_tools.add_spt3g_args(parser) - pipeline_tools.add_mc_args(parser) - - parser.add_argument( - "--outdir", required=False, default="out", help="Output directory" - ) - - parser.add_argument( - "--madam", - required=False, - action="store_true", - help="Use libmadam for map-making", - dest="use_madam", - ) - parser.add_argument( - "--no-madam", - required=False, - action="store_false", - help="Do not use libmadam for map-making [default]", - dest="use_madam", - ) - parser.set_defaults(use_madam=False) - - parser.add_argument( - "--focalplane", - required=False, - default=None, - help="Pickle file containing a dictionary of detector " - "properties. The keys of this dict are the detector " - "names, and each value is also a dictionary with keys " - '"quat" (4 element ndarray), "fwhm" (float, arcmin), ' - '"fknee" (float, Hz), "alpha" (float), and ' - '"NET" (float).', - ) - parser.add_argument( - "--freq", - required=True, - help="Comma-separated list of frequencies with identical focal planes." - " They override the bandpasses in the focalplane for the purpose of" - " scaling the atmospheric signal but not for simulating the sky signal.", - ) - - try: - args = parser.parse_args() - except SystemExit: - sys.exit(0) - - if args.tidas is not None: - if not tidas_available: - raise RuntimeError("TIDAS not found- cannot export") - - if args.spt3g is not None: - if not spt3g_available: - raise RuntimeError("SPT3G not found- cannot export") - - if len(args.freq.split(",")) != 1: - # Multi frequency run. We don't support multiple copies of - # scanned signal. - if args.input_map: - raise RuntimeError( - "Multiple frequencies are not supported when scanning from a map" - ) - - if args.simulate_atmosphere and args.weather is None: - raise RuntimeError("Cannot simulate atmosphere without a TOAST weather file") - - if comm.world_rank == 0: - log.info("All parameters:") - for ag in vars(args): - log.info("{} = {}".format(ag, getattr(args, ag))) - - if args.group_size: - comm = Comm(groupsize=args.group_size) - - if comm.world_rank == 0: - os.makedirs(args.outdir, exist_ok=True) - - timer.stop() - if comm.world_rank == 0: - timer.report("Parsed parameters") - - return args, comm - - -@function_timer -def load_focalplanes(args, comm, schedules): - """Attach a focalplane to each of the schedules. - - Args: - schedules (list) : List of Schedule instances. - Each schedule has two members, telescope - and ceslist, a list of CES objects. - Returns: - detweights (dict) : Inverse variance noise weights for every - detector across all focal planes. In [K_CMB^-2]. - They can be used to bin the TOD. - """ - timer = Timer() - timer.start() - - # Load focalplane information - - focalplanes = [] - if comm.world_rank == 0: - for fpfile in args.focalplane.split(","): - focalplanes.append( - pipeline_tools.Focalplane( - fname_pickle=fpfile, - sample_rate=args.sample_rate, - radius_deg=args.focalplane_radius_deg, - ) - ) - if comm.comm_world is not None: - focalplanes = comm.comm_world.bcast(focalplanes) - - if len(focalplanes) == 1 and len(schedules) > 1: - focalplanes *= len(schedules) - if len(focalplanes) != len(schedules): - raise RuntimeError( - "Number of focalplanes must equal number of schedules or be 1." - ) - - # Append a focal plane and telescope to each entry in the schedules - # list and assemble a detector weight dictionary that represents all - # detectors in all focalplanes - detweights = {} - for schedule, focalplane in zip(schedules, focalplanes): - schedule.telescope.focalplane = focalplane - detweights.update(schedule.telescope.focalplane.detweights) - - timer.stop() - if comm.world_rank == 0: - timer.report("Loading focalplanes") - return detweights - - -@function_timer -def create_observation(args, comm, telescope, ces, verbose=True): - """Create a TOAST observation. - - Create an observation for the CES scan - - Args: - args : argparse arguments - comm : TOAST communicator - ces (CES) : One constant elevation scan - - """ - focalplane = telescope.focalplane - site = telescope.site - weather = site.weather - noise = focalplane.noise - totsamples = int((ces.stop_time - ces.start_time) * args.sample_rate) - - # create the TOD for this observation - - if comm.comm_group is not None: - ndetrank = comm.comm_group.size - else: - ndetrank = 1 - - if args.el_nod_deg and (ces.subscan == 0 or args.el_nod_every_scan): - el_nod = args.el_nod_deg - else: - el_nod = None - - try: - tod = TODGround( - comm.comm_group, - focalplane.detquats, - totsamples, - detranks=ndetrank, - boresight_angle=ces.boresight_angle, - firsttime=ces.start_time, - rate=args.sample_rate, - site_lon=site.lon, - site_lat=site.lat, - site_alt=site.alt, - azmin=ces.azmin, - azmax=ces.azmax, - el=ces.el, - el_nod=el_nod, - start_with_elnod=args.start_with_el_nod, - end_with_elnod=args.end_with_el_nod, - el_mod_step=args.el_mod_step_deg, - el_mod_rate=args.el_mod_rate_hz, - el_mod_amplitude=args.el_mod_amplitude_deg, - el_mod_sine=args.el_mod_sine, - scanrate=args.scan_rate, - scanrate_el=args.scan_rate_el, - scan_accel=args.scan_accel, - scan_accel_el=args.scan_accel_el, - cosecant_modulation=args.scan_cosecant_modulate, - CES_start=None, - CES_stop=None, - sun_angle_min=args.sun_angle_min, - coord=args.coord, - sampsizes=None, - report_timing=args.debug, - hwprpm=args.hwp_rpm, - hwpstep=args.hwp_step_deg, - hwpsteptime=args.hwp_step_time_s, - ) - except RuntimeError as e: - raise RuntimeError( - 'Failed to create TOD for {}-{}-{}: "{}"' - "".format(ces.name, ces.scan, ces.subscan, e) - ) - - # Create the observation - - obs = {} - obs["name"] = "CES-{}-{}-{}-{}-{}".format( - site.name, telescope.name, ces.name, ces.scan, ces.subscan - ) - obs["tod"] = tod - obs["baselines"] = None - obs["noise"] = copy.deepcopy(noise) - obs["id"] = int(ces.mjdstart * 10000) - obs["intervals"] = tod.subscans - obs["site"] = site - obs["site_name"] = site.name - obs["site_id"] = site.id - obs["altitude"] = site.alt - obs["weather"] = site.weather - obs["telescope"] = telescope - obs["telescope_name"] = telescope.name - obs["telescope_id"] = telescope.id - obs["focalplane"] = telescope.focalplane.detector_data - obs["fpradius"] = telescope.focalplane.radius - obs["start_time"] = ces.start_time - obs["season"] = ces.season - obs["date"] = ces.start_date - obs["MJD"] = ces.mjdstart - obs["rising"] = ces.rising - obs["mindist_sun"] = ces.mindist_sun - obs["mindist_moon"] = ces.mindist_moon - obs["el_sun"] = ces.el_sun - return obs - - -@function_timer -def create_observations(args, comm, schedules): - """Create and distribute TOAST observations for every CES in - schedules. - - Args: - schedules (iterable) : a list of Schedule objects. - """ - log = Logger.get() - timer = Timer() - timer.start() - - data = Data(comm) - - # Loop over the schedules, distributing each schedule evenly across - # the process groups. For now, we'll assume that each schedule has - # the same number of operational days and the number of process groups - # matches the number of operational days. Relaxing these constraints - # will cause the season break to occur on different process groups - # for different schedules and prevent splitting the communicator. - - for schedule in schedules: - - telescope = schedule.telescope - all_ces = schedule.ceslist - nces = len(all_ces) - - breaks = pipeline_tools.get_breaks(comm, all_ces, args) - - groupdist = distribute_uniform(nces, comm.ngroups, breaks=breaks) - group_firstobs = groupdist[comm.group][0] - group_numobs = groupdist[comm.group][1] - - for ices in range(group_firstobs, group_firstobs + group_numobs): - obs = create_observation(args, comm, telescope, all_ces[ices]) - data.obs.append(obs) - - if comm.comm_world is None or comm.comm_group.rank == 0: - log.info("Group # {:4} has {} observations.".format(comm.group, len(data.obs))) - - if len(data.obs) == 0: - raise RuntimeError( - "Too many tasks. Every MPI task must " - "be assigned to at least one observation." - ) - - if comm.comm_world is not None: - comm.comm_world.barrier() - timer.stop() - if comm.world_rank == 0: - timer.report("Simulated scans") - - # Split the data object for each telescope for separate mapmaking. - # We could also split by site. - - if len(schedules) > 1: - telescope_data = data.split("telescope_name") - if len(telescope_data) == 1: - # Only one telescope available - telescope_data = [] - else: - telescope_data = [] - telescope_data.insert(0, ("all", data)) - return data, telescope_data - - -def setup_sigcopy(args): - """Determine if an extra copy of the atmospheric signal is needed. - - When we simulate multichroic focal planes, the frequency-independent - part of the atmospheric noise is simulated first and then the - frequency scaling is applied to a copy of the atmospheric noise. - """ - if len(args.freq.split(",")) == 1: - totalname = "total" - totalname_freq = "total" - else: - totalname = "total" - totalname_freq = "total_freq" - - return totalname, totalname_freq - - -@function_timer -def setup_output(args, comm, mc, freq): - outpath = "{}/{:08}/{:03}".format(args.outdir, mc, int(freq)) - if comm.world_rank == 0: - os.makedirs(outpath, exist_ok=True) - return outpath - - -def main(): - log = Logger.get() - gt = GlobalTimers.get() - gt.start("toast_ground_sim (total)") - timer0 = Timer() - timer0.start() - - mpiworld, procs, rank, comm = pipeline_tools.get_comm() - - args, comm = parse_arguments(comm) - - if args.use_madam: - # Initialize madam parameters - madampars = pipeline_tools.setup_madam(args) - - # Load and broadcast the schedule file - - schedules = pipeline_tools.load_schedule(args, comm) - - # Load the weather and append to schedules - - pipeline_tools.load_weather(args, comm, schedules) - - # load or simulate the focalplane - - detweights = load_focalplanes(args, comm, schedules) - - # Create the TOAST data object to match the schedule. This will - # include simulating the boresight pointing. - - data, telescope_data = create_observations(args, comm, schedules) - - # Split the communicator for day and season mapmaking - - time_comms = pipeline_tools.get_time_communicators(args, comm, data) - - # Expand boresight quaternions into detector pointing weights and - # pixel numbers - - pipeline_tools.expand_pointing(args, comm, data) - - # Optionally rewrite the noise PSD:s in each observation to include - # elevation-dependence - - pipeline_tools.get_elevation_noise(args, comm, data) - - # Purge the pointing if we are NOT going to export the - # data to a TIDAS volume - if (args.tidas is None) and (args.spt3g is None): - for ob in data.obs: - tod = ob["tod"] - tod.free_radec_quats() - - # Prepare auxiliary information for distributed map objects - - if args.pysm_model: - focalplanes = [s.telescope.focalplane.detector_data for s in schedules] - signalname = pipeline_tools.simulate_sky_signal( - args, comm, data, focalplanes, "signal" - ) - else: - signalname = pipeline_tools.scan_sky_signal(args, comm, data, "signal") - - # Set up objects to take copies of the TOD at appropriate times - - totalname, totalname_freq = setup_sigcopy(args) - - # Loop over Monte Carlos - - firstmc = args.MC_start - nsimu = args.MC_count - - freqs = [float(freq) for freq in args.freq.split(",")] - nfreq = len(freqs) - - for mc in range(firstmc, firstmc + nsimu): - - pipeline_tools.simulate_atmosphere(args, comm, data, mc, totalname) - - # Loop over frequencies with identical focal planes and identical - # atmospheric noise. - - for ifreq, freq in enumerate(freqs): - - if comm.world_rank == 0: - log.info( - "Processing frequency {}GHz {} / {}, MC = {}".format( - freq, ifreq + 1, nfreq, mc - ) - ) - - # Make a copy of the atmosphere so we can scramble the gains and apply - # frequency-dependent scaling. - pipeline_tools.copy_signal(args, comm, data, totalname, totalname_freq) - - pipeline_tools.scale_atmosphere_by_frequency( - args, comm, data, freq=freq, mc=mc, cache_name=totalname_freq - ) - - pipeline_tools.update_atmospheric_noise_weights(args, comm, data, freq, mc) - - # Add previously simulated sky signal to the atmospheric noise. - - pipeline_tools.add_signal( - args, comm, data, totalname_freq, signalname, purge=(nsimu == 1) - ) - - mcoffset = ifreq * 1000000 - - pipeline_tools.simulate_noise( - args, comm, data, mc + mcoffset, totalname_freq - ) - - pipeline_tools.simulate_sss(args, comm, data, mc + mcoffset, totalname_freq) - - pipeline_tools.scramble_gains( - args, comm, data, mc + mcoffset, totalname_freq - ) - - if (mc == firstmc) and (ifreq == 0): - # For the first realization and frequency, optionally - # export the timestream data. - pipeline_tools.output_tidas(args, comm, data, totalname) - pipeline_tools.output_spt3g(args, comm, data, totalname) - - outpath = setup_output(args, comm, mc + mcoffset, freq) - - # Bin and destripe maps - - if args.use_madam: - pipeline_tools.apply_madam( - args, - comm, - data, - madampars, - outpath, - detweights, - totalname_freq, - freq=freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=(mc == firstmc), - ) - else: - pipeline_tools.apply_mapmaker( - args, - comm, - data, - outpath, - totalname_freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=(mc == firstmc), - ) - - if ( - args.apply_polyfilter - or args.apply_polyfilter2D - or args.apply_groundfilter - ): - - # Filter signal - - pipeline_tools.apply_polyfilter(args, comm, data, totalname_freq) - - pipeline_tools.apply_polyfilter2D(args, comm, data, totalname_freq) - - pipeline_tools.apply_groundfilter(args, comm, data, totalname_freq) - - # Bin filtered maps - - if args.use_madam: - pipeline_tools.apply_madam( - args, - comm, - data, - madampars, - outpath, - detweights, - totalname_freq, - freq=freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=False, - extra_prefix="filtered", - bin_only=True, - ) - else: - pipeline_tools.apply_mapmaker( - args, - comm, - data, - outpath, - totalname_freq, - time_comms=time_comms, - telescope_data=telescope_data, - first_call=False, - extra_prefix="filtered", - bin_only=True, - ) - - gt.stop_all() - if mpiworld is not None: - mpiworld.barrier() - timer = Timer() - timer.start() - alltimers = gather_timers(comm=mpiworld) - if comm.world_rank == 0: - out = os.path.join(args.outdir, "timing") - dump_timing(alltimers, out) - timer.stop() - timer.report("Gather and dump timing info") - timer0.report_clear("toast_ground_sim.py") - return - - -if __name__ == "__main__": - try: - main() - except Exception: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - if procs == 1: - raise - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_ground_sim_simple.py b/pipelines/toast_ground_sim_simple.py deleted file mode 100644 index e97801d25..000000000 --- a/pipelines/toast_ground_sim_simple.py +++ /dev/null @@ -1,491 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -""" -Simpler version of the ground simulation script -""" - -import argparse -import dateutil.parser -import os -import pickle -import sys -import traceback - -import numpy as np - -from toast.mpi import get_world, Comm - -from toast.dist import distribute_uniform, Data - -from toast.utils import Logger, Environment, memreport - -from toast.timing import function_timer, GlobalTimers, Timer, gather_timers -from toast.timing import dump as dump_timing - -import toast.qarray as qa -from toast.tod import OpCacheCopy, plot_focalplane, OpCacheClear -from toast.todmap import TODGround - -from toast.pipeline_tools import ( - add_dist_args, - add_debug_args, - get_time_communicators, - get_comm, - add_polyfilter_args, - apply_polyfilter, - add_groundfilter_args, - apply_groundfilter, - add_atmosphere_args, - add_noise_args, - simulate_noise, - add_gainscrambler_args, - scramble_gains, - add_pointing_args, - expand_pointing, - add_madam_args, - setup_madam, - apply_madam, - add_sky_map_args, - add_pysm_args, - scan_sky_signal, - simulate_sky_signal, - copy_signal, - add_tidas_args, - output_tidas, - add_spt3g_args, - output_spt3g, - add_todground_args, - get_breaks, - Focalplane, - load_schedule, - add_mc_args, - add_binner_args, - init_binner, - apply_binner, -) - - -def parse_arguments(comm): - timer = Timer() - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Simulate ground-based boresight pointing. Simulate " - "and map astrophysical signal.", - fromfile_prefix_chars="@", - ) - - add_dist_args(parser) - add_debug_args(parser) - add_todground_args(parser) - add_pointing_args(parser) - add_polyfilter_args(parser) - add_groundfilter_args(parser) - add_gainscrambler_args(parser) - add_noise_args(parser) - add_sky_map_args(parser) - add_tidas_args(parser) - - parser.add_argument( - "--outdir", required=False, default="out", help="Output directory" - ) - - add_madam_args(parser) - add_binner_args(parser) - - parser.add_argument( - "--madam", - required=False, - action="store_true", - help="Use libmadam for map-making", - dest="use_madam", - ) - parser.add_argument( - "--no-madam", - required=False, - action="store_false", - help="Do not use libmadam for map-making [default]", - dest="use_madam", - ) - parser.set_defaults(use_madam=False) - - parser.add_argument( - "--focalplane", - required=False, - default=None, - help="Pickle file containing a dictionary of detector " - "properties. The keys of this dict are the detector " - "names, and each value is also a dictionary with keys " - '"quat" (4 element ndarray), "fwhm" (float, arcmin), ' - '"fknee" (float, Hz), "alpha" (float), and ' - '"NET" (float). For optional plotting, the key "color"' - " can specify a valid matplotlib color string.", - ) - - try: - args = parser.parse_args() - except SystemExit: - sys.exit(0) - - if args.tidas is not None: - if not tidas_available: - raise RuntimeError("TIDAS not found- cannot export") - - if comm.comm_world is None or comm.world_rank == 0: - log.info("All parameters:") - for ag in vars(args): - log.info("{} = {}".format(ag, getattr(args, ag))) - - if args.group_size: - comm = Comm(groupsize=args.group_size) - - if comm.comm_world is None or comm.comm_world.rank == 0: - os.makedirs(args.outdir, exist_ok=True) - - if comm.comm_world is None or comm.world_rank == 0: - timer.report_clear("Parsed parameters") - - return args, comm - - -def load_focalplane(args, comm, schedule): - focalplane = None - - # Load focalplane information - - if comm.comm_world is None or comm.comm_world.rank == 0: - if args.focalplane is None: - detector_data = {} - ZAXIS = np.array([0, 0, 1.0]) - # in this case, create a fake detector at the boresight - # with a pure white noise spectrum. - fake = {} - fake["quat"] = np.array([0, 0, 0, 1.0]) - fake["fwhm"] = 30.0 - fake["fknee"] = 0.0 - fake["fmin"] = 1e-9 - fake["alpha"] = 1.0 - fake["NET"] = 1.0 - fake["color"] = "r" - detector_data["bore1"] = fake - # Second detector at 22.5 degree polarization angle - fake2 = {} - zrot = qa.rotation(ZAXIS, np.radians(22.5)) - fake2["quat"] = qa.mult(fake["quat"], zrot) - fake2["fwhm"] = 30.0 - fake2["fknee"] = 0.0 - fake2["fmin"] = 1e-9 - fake2["alpha"] = 1.0 - fake2["NET"] = 1.0 - fake2["color"] = "r" - detector_data["bore2"] = fake2 - # Third detector at 45 degree polarization angle - fake3 = {} - zrot = qa.rotation(ZAXIS, np.radians(45)) - fake3["quat"] = qa.mult(fake["quat"], zrot) - fake3["fwhm"] = 30.0 - fake3["fknee"] = 0.0 - fake3["fmin"] = 1e-9 - fake3["alpha"] = 1.0 - fake3["NET"] = 1.0 - fake3["color"] = "r" - detector_data["bore3"] = fake3 - # Fourth detector at 67.5 degree polarization angle - fake4 = {} - zrot = qa.rotation(ZAXIS, np.radians(67.5)) - fake4["quat"] = qa.mult(fake["quat"], zrot) - fake4["fwhm"] = 30.0 - fake4["fknee"] = 0.0 - fake4["fmin"] = 1e-9 - fake4["alpha"] = 1.0 - fake4["NET"] = 1.0 - fake4["color"] = "r" - detector_data["bore4"] = fake4 - focalplane = Focalplane( - detector_data=detector_data, sample_rate=args.sample_rate - ) - else: - focalplane = Focalplane( - fname_pickle=args.focalplane, sample_rate=args.sample_rate - ) - if comm.comm_world is not None: - focalplane = comm.comm_world.bcast(focalplane, root=0) - - if args.debug: - if comm.comm_world is None or comm.comm_world.rank == 0: - outfile = "{}/focalplane.png".format(args.outdir) - plot_focalplane(focalplane, 6, 6, outfile) - - schedule.telescope.focalplane = focalplane - detweights = focalplane.detweights - - return detweights - - -def create_observations(args, comm, schedule): - """Simulate constant elevation scans. - - Simulate constant elevation scans at "site" matching entries in - "all_ces". Each operational day is assigned to a different - process group to allow making day maps. - - """ - timer = Timer() - log = Logger.get() - - data = Data(comm) - - telescope = schedule.telescope - site = telescope.site - focalplane = telescope.focalplane - all_ces = schedule.ceslist - nces = len(all_ces) - - breaks = get_breaks(comm, all_ces, args) - - nbreak = len(breaks) - - groupdist = distribute_uniform(nces, comm.ngroups, breaks=breaks) - group_firstobs = groupdist[comm.group][0] - group_numobs = groupdist[comm.group][1] - - if comm.comm_group is not None: - ndetrank = comm.comm_group.size - else: - ndetrank = 1 - - for ices in range(group_firstobs, group_firstobs + group_numobs): - ces = all_ces[ices] - totsamples = int((ces.stop_time - ces.start_time) * args.sample_rate) - - # create the single TOD for this observation - - try: - tod = TODGround( - comm.comm_group, - focalplane.detquats, - totsamples, - detranks=ndetrank, - firsttime=ces.start_time, - rate=args.sample_rate, - site_lon=site.lon, - site_lat=site.lat, - site_alt=site.alt, - azmin=ces.azmin, - azmax=ces.azmax, - el=ces.el, - scanrate=args.scan_rate, - scan_accel=args.scan_accel, - cosecant_modulation=args.scan_cosecant_modulate, - CES_start=None, - CES_stop=None, - sun_angle_min=args.sun_angle_min, - coord=args.coord, - sampsizes=None, - report_timing=args.debug, - ) - except RuntimeError as e: - raise RuntimeError("Failed to create the CES scan: {}".format(e)) - - # Create the (single) observation - - ob = {} - ob["name"] = "CES-{}-{}-{}".format(ces.name, ces.scan, ces.subscan) - ob["tod"] = tod - if len(tod.subscans) > 0: - ob["intervals"] = tod.subscans - else: - raise RuntimeError("{} has no valid intervals".format(ob["name"])) - ob["baselines"] = None - ob["noise"] = focalplane.noise - ob["id"] = int(ces.mjdstart * 10000) - - data.obs.append(ob) - - for ob in data.obs: - tod = ob["tod"] - tod.free_azel_quats() - - if comm.comm_world is None or comm.comm_group.rank == 0: - log.info("Group # {:4} has {} observations.".format(comm.group, len(data.obs))) - - if len(data.obs) == 0: - raise RuntimeError( - "Too many tasks. Every MPI task must " - "be assigned to at least one observation." - ) - - if comm.world_rank == 0: - timer.report_clear("Simulate scans") - - return data - - -def setup_sigcopy(args, comm, signalname): - """Setup for copying the signal so we can run filter+bin and Madam.""" - if args.use_madam: - signalname_madam = "signal_madam" - sigcopy_madam = OpCacheCopy(signalname, signalname_madam) - sigclear = OpCacheClear(signalname) - else: - signalname_madam = signalname - sigcopy_madam = None - sigclear = None - - return signalname_madam, sigcopy_madam, sigclear - - -def setup_output(args, comm): - outpath = "{}".format(args.outdir) - if comm.world_rank == 0: - if not os.path.isdir(outpath): - try: - os.makedirs(outpath) - except FileExistsError: - pass - return outpath - - -def copy_signal_madam(args, comm, data, sigcopy_madam): - """Make a copy of the TOD for Madam.""" - if sigcopy_madam is not None: - if comm.world_rank == 0: - print("Making a copy of the TOD for Madam", flush=args.flush) - sigcopy_madam.exec(data) - - return - - -def clear_signal(args, comm, data, sigclear): - if sigclear is not None: - if comm.world_rank == 0: - print("Clearing filtered signal") - sigclear.exec(data) - return - - -def main(): - log = Logger.get() - gt = GlobalTimers.get() - gt.start("toast_ground_sim (total)") - - mpiworld, procs, rank, comm = get_comm() - - args, comm = parse_arguments(comm) - - # Initialize madam parameters - - madampars = setup_madam(args) - - # Load and broadcast the schedule file - - schedule = load_schedule(args, comm)[0] - - # load or simulate the focalplane - - detweights = load_focalplane(args, comm, schedule) - - # Create the TOAST data object to match the schedule. This will - # include simulating the boresight pointing. - - data = create_observations(args, comm, schedule) - - # Expand boresight quaternions into detector pointing weights and - # pixel numbers - - expand_pointing(args, comm, data) - - # Scan input map - - signalname = scan_sky_signal(args, comm, data, "signal") - - # Simulate noise - - if signalname is None: - signalname = "signal" - mc = 0 - simulate_noise(args, comm, data, mc, signalname) - - # Set up objects to take copies of the TOD at appropriate times - - signalname_madam, sigcopy_madam, sigclear = setup_sigcopy(args, comm, signalname) - - npp, zmap = init_binner(args, comm, data, detweights) - - output_tidas(args, comm, data, signalname) - - outpath = setup_output(args, comm) - - # Make a copy of the signal for Madam - - copy_signal_madam(args, comm, data, sigcopy_madam) - - # Bin unprocessed signal for reference - - apply_binner(args, comm, data, npp, zmap, detweights, outpath, signalname) - - if args.apply_polyfilter or args.apply_groundfilter: - - # Filter signal - - apply_polyfilter(args, comm, data, signalname) - - apply_groundfilter(args, comm, data, signalname) - - # Bin the filtered signal - - apply_binner( - args, - comm, - data, - npp, - zmap, - detweights, - outpath, - signalname, - prefix="filtered", - ) - - data.obs[0]["tod"].cache.report() - - clear_signal(args, comm, data, sigclear) - - data.obs[0]["tod"].cache.report() - - # Now run Madam on the unprocessed copy of the signal - - if args.use_madam: - apply_madam(args, comm, data, madampars, outpath, detweights, signalname_madam) - - gt.stop_all() - if mpiworld is not None: - mpiworld.barrier() - timer = Timer() - timer.start() - alltimers = gather_timers(comm=mpiworld) - if comm.world_rank == 0: - out = os.path.join(args.outdir, "timing") - dump_timing(alltimers, out) - timer.report_clear("Gather and dump timing info") - return - - -if __name__ == "__main__": - try: - main() - except Exception: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - if procs == 1: - raise - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/pipelines/toast_map.py b/pipelines/toast_map.py deleted file mode 100644 index e912d9c1d..000000000 --- a/pipelines/toast_map.py +++ /dev/null @@ -1,478 +0,0 @@ -#!/usr/bin/env python3 - -# FIXME: Port this pipeline to 2.3. - - -# Copyright (c) 2015-2018 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -from toast.mpi import MPI, finalize - -import os -import sys -import time - -import re -import argparse -import traceback - -import pickle - -import numpy as np - -import toast -import toast.tod as tt -import toast.map as tm -import toast.todmap as ttm - -import toast.qarray as qa -import toast.timing as timing - -from toast.vis import set_backend - -if tt.tidas_available: - from toast.tod import tidas as tds - -if tt.spt3g_available: - from toast.tod import spt3g as s3g - - -def elapsed(mcomm, start, msg): - mcomm.barrier() - stop = MPI.Wtime() - dur = stop - start - if mcomm.rank == 0: - print("{}: {:.3f} s".format(msg, dur), flush=True) - return stop - - -def main(): - - if MPI.COMM_WORLD.rank == 0: - print("Running with {} processes".format(MPI.COMM_WORLD.size), flush=True) - - global_start = MPI.Wtime() - - parser = argparse.ArgumentParser( - description="Read existing data and make a simple map.", - fromfile_prefix_chars="@", - ) - - parser.add_argument( - "--groupsize", - required=False, - type=int, - default=0, - help="size of processor groups used to distribute " "observations", - ) - - parser.add_argument( - "--hwprpm", - required=False, - type=float, - default=0.0, - help="The rate (in RPM) of the HWP rotation", - ) - - parser.add_argument( - "--samplerate", - required=False, - default=100.0, - type=np.float, - help="Detector sample rate (Hz)", - ) - - parser.add_argument( - "--outdir", required=False, default="out", help="Output directory" - ) - - parser.add_argument( - "--nside", required=False, type=int, default=64, help="Healpix NSIDE" - ) - - parser.add_argument( - "--subnside", - required=False, - type=int, - default=8, - help="Distributed pixel sub-map NSIDE", - ) - - parser.add_argument( - "--coord", required=False, default="E", help="Sky coordinate system [C,E,G]" - ) - - parser.add_argument( - "--baseline", - required=False, - type=float, - default=60.0, - help="Destriping baseline length (seconds)", - ) - - parser.add_argument( - "--noisefilter", - required=False, - default=False, - action="store_true", - help="Destripe with the noise filter enabled", - ) - - parser.add_argument( - "--madam", - required=False, - default=False, - action="store_true", - help="If specified, use libmadam for map-making", - ) - - parser.add_argument( - "--madampar", required=False, default=None, help="Madam parameter file" - ) - - parser.add_argument( - "--polyorder", - required=False, - type=int, - help="Polynomial order for the polyfilter", - ) - - parser.add_argument( - "--wbin_ground", - required=False, - type=float, - help="Ground template bin width [degrees]", - ) - - parser.add_argument( - "--flush", - required=False, - default=False, - action="store_true", - help="Flush every print statement.", - ) - - parser.add_argument( - "--tidas", required=False, default=None, help="Input TIDAS volume" - ) - - parser.add_argument( - "--tidas_detgroup", required=False, default=None, help="TIDAS detector group" - ) - - parser.add_argument( - "--spt3g", required=False, default=None, help="Input SPT3G data directory" - ) - - parser.add_argument( - "--spt3g_prefix", - required=False, - default=None, - help="SPT3G data frame file prefix", - ) - - parser.add_argument( - "--common_flag_mask", - required=False, - default=0, - type=np.uint8, - help="Common flag mask", - ) - - parser.add_argument( - "--debug", - required=False, - default=False, - action="store_true", - help="Write data distribution info and focalplane plot", - ) - - args = timing.add_arguments_and_parse(parser, timing.FILE(noquotes=True)) - # args = parser.parse_args(sys.argv) - - autotimer = timing.auto_timer("@{}".format(timing.FILE())) - - if (args.tidas is not None) and (args.spt3g is not None): - raise RuntimeError("Cannot read two datasets!") - - if (args.tidas is None) and (args.spt3g is None): - raise RuntimeError("No dataset specified!") - - if args.tidas is not None: - if not tt.tidas_available: - raise RuntimeError("TIDAS not found- cannot load") - - if args.spt3g is not None: - if not tt.spt3g_available: - raise RuntimeError("SPT3G not found- cannot load") - - groupsize = args.groupsize - if groupsize == 0: - groupsize = MPI.COMM_WORLD.size - - # Pixelization - - nside = args.nside - npix = 12 * args.nside * args.nside - subnside = args.subnside - if subnside > nside: - subnside = nside - subnpix = 12 * subnside * subnside - - # This is the 2-level toast communicator. - - if MPI.COMM_WORLD.size % groupsize != 0: - if MPI.COMM_WORLD.rank == 0: - print( - "WARNING: process groupsize does not evenly divide into " - "total number of processes", - flush=True, - ) - comm = toast.Comm(world=MPI.COMM_WORLD, groupsize=groupsize) - - # Create output directory - - mtime = MPI.Wtime() - - if comm.comm_world.rank == 0: - if not os.path.isdir(args.outdir): - os.makedirs(args.outdir) - - mtime = elapsed(comm.comm_world, mtime, "Creating output directory") - - # The distributed timestream data - - data = None - - if args.tidas is not None: - if args.tidas_detgroup is None: - raise RuntimeError("you must specify the detector group") - data = tds.load_tidas( - comm, - comm.group_size, - args.tidas, - "r", - args.tidas_detgroup, - tds.TODTidas, - group_dets=args.tidas_detgroup, - distintervals="chunks", - ) - - if args.spt3g is not None: - if args.spt3g_prefix is None: - raise RuntimeError("you must specify the frame file prefix") - data = s3g.load_spt3g( - comm, - comm.group_size, - args.spt3g, - args.spt3g_prefix, - s3g.obsweight_spt3g, - s3g.TOD3G, - ) - - mtime = elapsed(comm.comm_world, mtime, "Distribute data") - - # In debug mode, print out data distribution information - - if args.debug: - handle = None - if comm.comm_world.rank == 0: - handle = open("{}_distdata.txt".format(args.outdir), "w") - data.info(handle) - if comm.comm_world.rank == 0: - handle.close() - mtime = elapsed(comm.comm_world, mtime, "Dumping debug data distribution") - if comm.comm_world.rank == 0: - outfile = "{}_focalplane.png".format(args.outdir) - set_backend() - # Just plot the dets from the first TOD - temptod = data.obs[0]["tod"] - # FIXME: change this once we store det info in the metadata. - dfwhm = {x: 10.0 for x in temptod.detectors} - tt.plot_focalplane(temptod.detoffset(), 10.0, 10.0, outfile, fwhm=dfwhm) - comm.comm_world.barrier() - mtime = elapsed(comm.comm_world, mtime, "Plotting debug focalplane") - - # Compute pointing matrix - - pointing = tt.OpPointingHpix( - nside=args.nside, nest=True, mode="IQU", hwprpm=args.hwprpm - ) - pointing.exec(data) - - mtime = elapsed(comm.comm_world, mtime, "Expand pointing") - - # Mapmaking. - - # FIXME: We potentially have a different noise model for every - # observation. We need to have both spt3g and tidas format Noise - # classes which read the information from disk. Then the mapmaking - # operators need to get these noise weights from each observation. - detweights = {d: 1.0 for d in data.obs[0]["tod"].detectors} - - if not args.madam: - if comm.comm_world.rank == 0: - print("Not using Madam, will only make a binned map!", flush=True) - - # Filter data if desired - - if args.polyorder: - polyfilter = tt.OpPolyFilter( - order=args.polyorder, common_flag_mask=args.common_flag_mask - ) - polyfilter.exec(data) - mtime = elapsed(comm.comm_world, mtime, "Polynomial filtering") - - if args.wbin_ground: - groundfilter = tt.OpGroundFilter( - wbin=args.wbin_ground, common_flag_mask=args.common_flag_mask - ) - groundfilter.exec(data) - mtime = elapsed(comm.comm_world, mtime, "Ground template filtering") - - # Compute pixel space distribution - - lc = tm.OpLocalPixels() - localpix = lc.exec(data) - if localpix is None: - raise RuntimeError( - "Process {} has no hit pixels. Perhaps there are fewer " - "detectors than processes in the group?".format(comm.comm_world.rank) - ) - localsm = np.unique(np.floor_divide(localpix, subnpix)) - mtime = elapsed(comm.comm_world, mtime, "Compute local submaps") - - # construct distributed maps to store the covariance, - # noise weighted map, and hits - - mtime = MPI.Wtime() - invnpp = tm.DistPixels( - comm=comm.comm_world, - size=npix, - nnz=6, - dtype=np.float64, - submap=subnpix, - local=localsm, - ) - hits = tm.DistPixels( - comm=comm.comm_world, - size=npix, - nnz=1, - dtype=np.int64, - submap=subnpix, - local=localsm, - ) - zmap = tm.DistPixels( - comm=comm.comm_world, - size=npix, - nnz=3, - dtype=np.float64, - submap=subnpix, - local=localsm, - ) - - # compute the hits and covariance. - - invnpp.data.fill(0.0) - hits.data.fill(0) - - build_invnpp = tm.OpAccumDiag( - detweights=detweights, - invnpp=invnpp, - hits=hits, - common_flag_mask=args.common_flag_mask, - ) - build_invnpp.exec(data) - - invnpp.allreduce() - hits.allreduce() - mtime = elapsed(comm.comm_world, mtime, "Building hits and N_pp^-1") - - hits.write_healpix_fits("{}_hits.fits".format(args.outdir)) - invnpp.write_healpix_fits("{}_invnpp.fits".format(args.outdir)) - mtime = elapsed(comm.comm_world, mtime, "Writing hits and N_pp^-1") - - # invert it - tm.covariance_invert(invnpp, 1.0e-3) - mtime = elapsed(comm.comm_world, mtime, "Inverting N_pp^-1") - - invnpp.write_healpix_fits("{}_npp.fits".format(args.outdir)) - mtime = elapsed(comm.comm_world, mtime, "Writing N_pp") - - zmap.data.fill(0.0) - build_zmap = tm.OpAccumDiag( - zmap=zmap, detweights=detweights, common_flag_mask=args.common_flag_mask - ) - build_zmap.exec(data) - zmap.allreduce() - mtime = elapsed(comm.comm_world, mtime, "Building noise weighted map") - - tm.covariance_apply(invnpp, zmap) - mtime = elapsed(comm.comm_world, mtime, "Computing binned map") - - zmap.write_healpix_fits(os.path.join(args.outdir, "binned.fits")) - mtime = elapsed(comm.comm_world, mtime, "Writing binned map") - - else: - # Set up MADAM map making. - - pars = {} - pars["temperature_only"] = "F" - pars["force_pol"] = "T" - pars["kfirst"] = "T" - pars["concatenate_messages"] = "T" - pars["write_map"] = "T" - pars["write_binmap"] = "T" - pars["write_matrix"] = "T" - pars["write_wcov"] = "T" - pars["write_hits"] = "T" - pars["nside_cross"] = nside // 2 - pars["nside_submap"] = subnside - - if args.madampar is not None: - pat = re.compile(r"\s*(\S+)\s*=\s*(\S+(\s+\S+)*)\s*") - comment = re.compile(r"^#.*") - with open(args.madampar, "r") as f: - for line in f: - if comment.match(line) is None: - result = pat.match(line) - if result is not None: - key, value = result.group(1), result.group(2) - pars[key] = value - - pars["base_first"] = args.baseline - pars["nside_map"] = nside - if args.noisefilter: - pars["kfilter"] = "T" - else: - pars["kfilter"] = "F" - pars["fsample"] = args.samplerate - - madam = tm.OpMadam( - params=pars, detweights=detweights, common_flag_mask=args.common_flag_mask - ) - madam.exec(data) - mtime = elapsed(comm.comm_world, mtime, "Madam mapmaking") - - comm.comm_world.barrier() - stop = MPI.Wtime() - dur = stop - global_start - if comm.comm_world.rank == 0: - print("Total Time: {:.2f} seconds".format(dur), flush=True) - return - - -if __name__ == "__main__": - try: - main() - tman = timing.timing_manager() - tman.report() - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(MPI.COMM_WORLD.rank, x) for x in lines] - print("".join(lines), flush=True) - toast.raise_error(6) # typical error code for SIGABRT - MPI.COMM_WORLD.Abort(6) - finalize() diff --git a/pipelines/toast_satellite_sim.py b/pipelines/toast_satellite_sim.py deleted file mode 100644 index cf11a75fa..000000000 --- a/pipelines/toast_satellite_sim.py +++ /dev/null @@ -1,510 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2015-2020 by the parties listed in the AUTHORS file. -# All rights reserved. Use of this source code is governed by -# a BSD-style license that can be found in the LICENSE file. - -""" -This script runs a satellite simulation and makes a map. -""" - -import os -import sys -import re -import argparse -import traceback - -import pickle - -import numpy as np - -from astropy.io import fits - -from toast.mpi import get_world, Comm - -from toast.dist import distribute_uniform, Data - -from toast.utils import Logger, Environment - -from toast.vis import set_backend - -from toast.timing import function_timer, GlobalTimers, Timer, gather_timers -from toast.timing import dump as dump_timing - -from toast.tod import regular_intervals, plot_focalplane, OpApplyGain -from toast.todmap import TODSatellite, slew_precession_axis - -from toast import pipeline_tools - - -def parse_arguments(comm, procs): - log = Logger.get() - - parser = argparse.ArgumentParser( - description="Simulate satellite boresight pointing and make a map.", - fromfile_prefix_chars="@", - ) - - pipeline_tools.add_dist_args(parser) - pipeline_tools.add_pointing_args(parser) - pipeline_tools.add_tidas_args(parser) - pipeline_tools.add_spt3g_args(parser) - pipeline_tools.add_dipole_args(parser) - pipeline_tools.add_sky_map_args(parser) - pipeline_tools.add_pysm_args(parser) - pipeline_tools.add_mc_args(parser) - pipeline_tools.add_noise_args(parser) - pipeline_tools.add_todsatellite_args(parser) - pipeline_tools.add_conviqt_args(parser) - - parser.add_argument( - "--outdir", required=False, default="out", help="Output directory" - ) - parser.add_argument( - "--debug", - required=False, - default=False, - action="store_true", - help="Write diagnostics", - ) - - pipeline_tools.add_madam_args(parser) - pipeline_tools.add_mapmaker_args(parser) - pipeline_tools.add_binner_args(parser) - - parser.add_argument( - "--madam", - required=False, - action="store_true", - help="Use libmadam for map-making", - dest="use_madam", - ) - parser.add_argument( - "--no-madam", - required=False, - action="store_false", - help="Do not use libmadam for map-making [default]", - dest="use_madam", - ) - parser.set_defaults(use_madam=False) - - parser.add_argument( - "--focalplane", - required=False, - default=None, - help="Pickle file containing a dictionary of detector properties. " - "The keys of this dict are the detector names, and each value is also " - 'a dictionary with keys "quat" (4 element ndarray), "fwhm" ' - '(float, arcmin), "fknee" (float, Hz), "alpha" (float), and "NET" ' - '(float). For optional plotting, the key "color" can specify a ' - "valid matplotlib color string.", - ) - - parser.add_argument( - "--gain", - required=False, - default=None, - help="Calibrate the input timelines with a set of gains from a" - "FITS file containing 3 extensions:" - "HDU named DETECTORS : table with list of detector names in a column named DETECTORS" - "HDU named TIME: table with common timestamps column named TIME" - "HDU named GAINS: 2D image of floats with one row per detector and one column per value.", - ) - - try: - args = parser.parse_args() - except SystemExit: - sys.exit() - - if comm.world_rank == 0: - log.info("\n") - log.info("All parameters:") - for ag in vars(args): - log.info("{} = {}".format(ag, getattr(args, ag))) - log.info("\n") - - groupsize = args.group_size - if groupsize is None or groupsize <= 0: - groupsize = procs - - # This is the 2-level toast communicator. - comm = Comm(groupsize=groupsize) - - return args, comm, groupsize - - -def load_focalplane(args, comm): - """Load focalplane information""" - timer = Timer() - gain = None - fp = None - if comm.world_rank == 0: - if args.focalplane is None: - # in this case, create a fake detector at the boresight - # with a pure white noise spectrum. - fake = {} - fake["quat"] = np.array([0.0, 0.0, 1.0, 0.0]) - fake["fwhm"] = 30.0 - fake["fknee"] = 0.0 - fake["fmin"] = 1.0e-5 - fake["alpha"] = 1.0 - fake["NET"] = 1.0 - fake["polangle_deg"] = 0 - fake["color"] = "r" - fp = {} - fp["bore"] = fake - else: - with open(args.focalplane, "rb") as p: - fp = pickle.load(p) - - if args.gain is not None: - gain = {} - with fits.open(args.gain) as f: - gain["TIME"] = np.array(f["TIME"].data["TIME"]) - for i_det, det_name in f["DETECTORS"].data["DETECTORS"]: - gain[det_name] = np.array(f["GAINS"].data[i_det, :]) - - if comm.comm_world is not None: - if args.gain is not None: - gain = comm.comm_world.bcast(gain, root=0) - fp = comm.comm_world.bcast(fp, root=0) - - timer.stop() - if comm.world_rank == 0: - timer.report("Create focalplane ({} dets)".format(len(fp.keys()))) - - if args.debug: - if comm.world_rank == 0: - outfile = os.path.join(args.outdir, "focalplane.png") - set_backend() - dquats = {x: fp[x]["quat"] for x in fp.keys()} - dfwhm = {x: fp[x]["fwhm"] for x in fp.keys()} - plot_focalplane(dquats, 10.0, 10.0, outfile, fwhm=dfwhm) - - # For purposes of this simulation, we use detector noise - # weights based on the NET (white noise level). If the destriping - # baseline is too long, this will not be the best choice. - - detweights = {} - for d in fp.keys(): - net = fp[d]["NET"] - detweights[d] = 1.0 / (args.sample_rate * net * net) - - return fp, gain, detweights - - -def create_observations(args, comm, focalplane, groupsize): - timer = Timer() - timer.start() - log = Logger.get() - - if groupsize > len(focalplane.keys()): - if comm.world_rank == 0: - log.error("process group is too large for the number of detectors") - comm.comm_world.Abort() - - # Detector information from the focalplane - - detectors = sorted(focalplane.keys()) - detquats = {} - detindx = None - if "index" in focalplane[detectors[0]]: - detindx = {} - - for d in detectors: - detquats[d] = focalplane[d]["quat"] - if detindx is not None: - detindx[d] = focalplane[d]["index"] - - # Distribute the observations uniformly - - groupdist = distribute_uniform(args.obs_num, comm.ngroups) - - # Compute global time and sample ranges of all observations - - obsrange = regular_intervals( - args.obs_num, - args.start_time, - 0, - args.sample_rate, - 3600 * args.obs_time_h, - 3600 * args.gap_h, - ) - - noise = pipeline_tools.get_analytic_noise(args, comm, focalplane) - - # The distributed timestream data - - data = Data(comm) - - # Every process group creates its observations - - group_firstobs = groupdist[comm.group][0] - group_numobs = groupdist[comm.group][1] - - for ob in range(group_firstobs, group_firstobs + group_numobs): - tod = TODSatellite( - comm.comm_group, - detquats, - obsrange[ob].samples, - coord=args.coord, - firstsamp=obsrange[ob].first, - firsttime=obsrange[ob].start, - rate=args.sample_rate, - spinperiod=args.spin_period_min, - spinangle=args.spin_angle_deg, - precperiod=args.prec_period_min, - precangle=args.prec_angle_deg, - detindx=detindx, - detranks=comm.group_size, - hwprpm=args.hwp_rpm, - hwpstep=args.hwp_step_deg, - hwpsteptime=args.hwp_step_time_s, - ) - - obs = {} - obs["name"] = "science_{:05d}".format(ob) - obs["tod"] = tod - obs["intervals"] = None - obs["baselines"] = None - obs["noise"] = noise - obs["id"] = ob - obs["focalplane"] = pipeline_tools.Focalplane(focalplane) - - data.obs.append(obs) - - if comm.world_rank == 0: - timer.report_clear("Read parameters, compute data distribution") - - # Since we are simulating noise timestreams, we want - # them to be contiguous and reproducible over the whole - # observation. We distribute data by detector within an - # observation, so ensure that our group size is not larger - # than the number of detectors we have. - - # we set the precession axis now, which will trigger calculation - # of the boresight pointing. - - for ob in range(group_numobs): - curobs = data.obs[ob] - tod = curobs["tod"] - - # Get the global sample offset from the original distribution of - # intervals - obsoffset = obsrange[group_firstobs + ob].first - - # Constantly slewing precession axis - degday = 360.0 / 365.25 - precquat = np.empty(4 * tod.local_samples[1], dtype=np.float64).reshape((-1, 4)) - slew_precession_axis( - precquat, - firstsamp=(obsoffset + tod.local_samples[0]), - samplerate=args.sample_rate, - degday=degday, - ) - - tod.set_prec_axis(qprec=precquat) - del precquat - - if comm.world_rank == 0: - timer.report_clear("Construct boresight pointing") - - return data - - -def main(): - env = Environment.get() - log = Logger.get() - gt = GlobalTimers.get() - gt.start("toast_satellite_sim (total)") - timer0 = Timer() - timer0.start() - - mpiworld, procs, rank, comm = pipeline_tools.get_comm() - args, comm, groupsize = parse_arguments(comm, procs) - - # Parse options - - tmr = Timer() - tmr.start() - - if comm.world_rank == 0: - os.makedirs(args.outdir, exist_ok=True) - - focalplane, gain, detweights = load_focalplane(args, comm) - if comm.world_rank == 0: - tmr.report_clear("Load focalplane") - - data = create_observations(args, comm, focalplane, groupsize) - if comm.world_rank == 0: - tmr.report_clear("Create observations") - - pipeline_tools.expand_pointing(args, comm, data) - if comm.world_rank == 0: - tmr.report_clear("Expand pointing") - - signalname = None - if args.pysm_model: - skyname = pipeline_tools.simulate_sky_signal( - args, comm, data, [focalplane], "signal" - ) - else: - skyname = pipeline_tools.scan_sky_signal(args, comm, data, "signal") - if skyname is not None: - signalname = skyname - if comm.world_rank == 0: - tmr.report_clear("Simulate sky signal") - - # NOTE: Conviqt could use different input file names for different - # Monte Carlo indices, but the operator would need to be invoked within - # the Monte Carlo loop. - skyname = pipeline_tools.apply_conviqt( - args, - comm, - data, - "signal", - mc=args.MC_start, - ) - if skyname is not None: - signalname = skyname - if comm.world_rank == 0: - tmr.report_clear("Apply beam convolution") - - diponame = pipeline_tools.simulate_dipole(args, comm, data, "signal") - if diponame is not None: - signalname = diponame - if comm.world_rank == 0: - tmr.report_clear("Simulate dipole") - - # in debug mode, print out data distribution information - if args.debug: - handle = None - if comm.world_rank == 0: - handle = open(os.path.join(args.outdir, "distdata.txt"), "w") - data.info(handle) - if comm.world_rank == 0: - handle.close() - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear("Dumping data distribution") - - # in debug mode, print out data distribution information - if args.debug: - handle = None - if comm.world_rank == 0: - handle = open(os.path.join(args.outdir, "distdata.txt"), "w") - data.info(handle) - if comm.world_rank == 0: - handle.close() - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear("Dumping data distribution") - - # Mapmaking. - - if args.use_madam: - # Initialize madam parameters - madampars = pipeline_tools.setup_madam(args) - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear("Initialize madam map-making") - - # Loop over Monte Carlos - - firstmc = args.MC_start - nmc = args.MC_count - - for mc in range(firstmc, firstmc + nmc): - mctmr = Timer() - mctmr.start() - - # create output directory for this realization - outpath = os.path.join(args.outdir, "mc_{:03d}".format(mc)) - - pipeline_tools.simulate_noise( - args, comm, data, mc, "tot_signal", overwrite=True - ) - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear(" Simulate noise {:04d}".format(mc)) - - # add sky signal - pipeline_tools.add_signal(args, comm, data, "tot_signal", signalname) - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear(" Add sky signal {:04d}".format(mc)) - - if gain is not None: - op_apply_gain = OpApplyGain(gain, name="tot_signal") - op_apply_gain.exec(data) - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear(" Apply gains {:04d}".format(mc)) - - if mc == firstmc: - # For the first realization, optionally export the - # timestream data. If we had observation intervals defined, - # we could pass "use_interval=True" to the export operators, - # which would ensure breaks in the exported data at - # acceptable places. - pipeline_tools.output_tidas(args, comm, data, "tot_signal") - pipeline_tools.output_spt3g(args, comm, data, "tot_signal") - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear(" Write TOD snapshot {:04d}".format(mc)) - - if args.use_madam: - pipeline_tools.apply_madam( - args, comm, data, madampars, outpath, detweights, "tot_signal" - ) - else: - pipeline_tools.apply_mapmaker(args, comm, data, outpath, "tot_signal") - - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - tmr.report_clear(" Map-making {:04d}".format(mc)) - - if comm.comm_world is not None: - comm.comm_world.barrier() - if comm.world_rank == 0: - mctmr.report_clear(" Monte Carlo loop {:04d}".format(mc)) - - gt.stop_all() - if comm.comm_world is not None: - comm.comm_world.barrier() - tmr.stop() - tmr.clear() - tmr.start() - alltimers = gather_timers(comm=comm.comm_world) - if comm.world_rank == 0: - out = os.path.join(args.outdir, "timing") - dump_timing(alltimers, out) - tmr.stop() - tmr.report("Gather and dump timing info") - timer0.report_clear("toast_satellite_sim.py") - return - - -if __name__ == "__main__": - try: - main() - except Exception: - # We have an unhandled exception on at least one process. Print a stack - # trace for this process and then abort so that all processes terminate. - mpiworld, procs, rank = get_world() - if procs == 1: - raise - exc_type, exc_value, exc_traceback = sys.exc_info() - lines = traceback.format_exception(exc_type, exc_value, exc_traceback) - lines = ["Proc {}: {}".format(rank, x) for x in lines] - print("".join(lines), flush=True) - if mpiworld is not None: - mpiworld.Abort(6) diff --git a/platforms/README.md b/platforms/README.md new file mode 100644 index 000000000..a094a441c --- /dev/null +++ b/platforms/README.md @@ -0,0 +1,158 @@ +# Example Configurations + +This directory contains a variety of examples for how to configure toast with +cmake using a variety of upstream dependencies. Below we cover the most common +use cases. + +## Building with Conda Compilers + +If you have a base conda environment loaded, you can create a new conda env +with all toast dependencies by doing: + + $> mkdir build + $> cd build + $> ../platforms/conda_dev_setup.sh + +Where "new env" is the name or path of the environment to create and populate +with dependencies. Next, activate the new environment. + + $> conda activate + +And now configure toast to use all the conda-provided dependencies and install +to the conda prefix: + + $> cd build + $> ../platforms/conda_dev.sh + $> make -j 4 install + +## Using LLVM for GPU Support with OpenMP Target + +When using OpenMP target offload, the internal compiled extension is built with +a compiler that support both the modern OpenMP standard and the GPU device on +the system. TOAST also requires a BLAS / LAPACK library, and this must be +compatible with the OpenMP implementation used to build TOAST. + +For this example, we will use LLVM to build all our compiled dependencies. The +following example is on the perlmutter system at NERSC. First load the LLVM +environment: + + $> module swap PrgEnv-gnu PrgEnv-llvm + $> module swap llvm llvm/17 + # Load conda base just to get python and venv module + $> module load python + +Next, setup a build directory (for example, on scratch) and decide where to +install the software. For the purposes of this example, we will build software +in `${SCRATCH}/build_llvm` and install software to `${HOME}/toast_llvm`. + + $> cd ${SCRATCH}/build_llvm + $> MPICC=cc \ + ${HOME}/git/toast/platforms/perlmutter-llvm_setup.sh \ + ${HOME}/toast_llvm | tee log 2>&1 + +This will create a virtualenv in `${HOME}/toast_llvm` and then install our +compiled dependencies into that directory. Next we activate this virtualenv +and add it to our shared library search path: + + $> source ${HOME}/toast_llvm/bin/activate + $> export LD_LIBRARY_PATH=${HOME}/toast_llvm/lib:${LD_LIBRARY_PATH} + +Now we are finally ready to compile toast itself. This script will run cmake +and configure the installation to the dependencies in our virtualenv: + + $> cd ${SCRATCH}/build_llvm + $> ${HOME}/git/toast/platforms/perlmutter-llvm.sh + $> make -j 4 install + +As always, run the unit tests to verify the installation. You can enable GPU +use by setting `TOAST_GPU_OPENMP=1` and `OMP_TARGET_OFFLOAD=MANDATORY` in your +shell environment. + +### Running a Simple Benchmark + +This example is run on a compute node (i.e. get an interactive node with +salloc). First we try the ground-based benchmark: + + # Create the ground benchmark inputs + OMP_NUM_THREADS=4 srun -n 1 toast_benchmark_ground_setup --work_dir inputs + + # Run the "tiny" case on the CPU + OMP_NUM_THREADS=4 OMP_TARGET_OFFLOAD=DISABLED srun -n 4 \ + toast_benchmark_ground \ + --input_dir inputs \ + --out_dir out_tiny_cpu \ + --case tiny | tee log_tiny_cpu 2>&1 + + # Run the "tiny" case on the GPU + OMP_NUM_THREADS=4 OMP_TARGET_OFFLOAD=MANDATORY TOAST_GPU_OPENMP=1 srun -n 4 \ + toast_benchmark_ground \ + --input_dir inputs \ + --out_dir out_tiny_gpu \ + --case tiny | tee log_tiny_gpu 2>&1 + +We can also run the satellite case: + + # Run the "tiny" case on the CPU. + # NOTE: the first run will create some input files, + # which takes some additional time. + OMP_NUM_THREADS=4 OMP_TARGET_OFFLOAD=DISABLED srun -n 4 \ + toast_benchmark_satellite \ + --out_dir out_tiny_cpu \ + --case tiny | tee log_tiny_cpu 2>&1 + + # Run the "tiny" case on the GPU + OMP_NUM_THREADS=4 OMP_TARGET_OFFLOAD=MANDATORY TOAST_GPU_OPENMP=1 srun -n 4 \ + toast_benchmark_satellite \ + --out_dir out_tiny_gpu \ + --case tiny | tee log_tiny_gpu 2>&1 + +## Using NVHPC for GPU Support with OpenMP Target + +When using OpenMP target offload, the internal compiled extension is built with +a compiler (such as the NVHPC SDK compilers) that support both the modern +OpenMP standard and the GPU device on the system. TOAST also requires a BLAS / +LAPACK library, and this must be compatible with the OpenMP implementation used +to build TOAST. + +For this example, we will use the NVHPC-provided BLAS and LAPACK libraries and +compile other dependencies with the NVHPC compilers. The following example is +on the perlmutter system at NERSC: + + $> module load python + $> module use /global/common/software/cmb/perlmutter/nvhpc/modulefiles + $> module load nvhpc-nompi/23.9 + +Next, setup a build directory (for example, on scratch) and decide where to +install the software. For the purposes of this example, we will build software +in `${SCRATCH}/build_nvhpc` and install software to `${HOME}/toast_nvhpc`. + + $> cd ${SCRATCH}/build_nvhpc + $> MPICC=cc \ + ${HOME}/git/toast/platforms/perlmutter-nvhpc_setup.sh \ + ${HOME}/toast_nvhpc | tee log 2>&1 + +This will create a virtualenv in `${HOME}/toast_nvhpc` and then install our +compiled dependencies into that directory. Next we activate this virtualenv +and add it to our shared library search path: + + $> source ${HOME}/toast_nvhpc/bin/activate + $> export LD_LIBRARY_PATH=${HOME}/toast_nvhpc/lib:${LD_LIBRARY_PATH} + +Now we are finally ready to compile toast itself. This script will run cmake +and configure the installation to the dependencies in our virtualenv: + + $> cd ${SCRATCH}/build_nvhpc + $> ${HOME}/git/toast/platforms/perlmutter-nvhpc.sh + $> make -j 4 install + +As always, run the unit tests to verify the installation. You can enable GPU +use by setting `TOAST_GPU_OPENMP=1` and `OMP_TARGET_OFFLOAD=MANDATORY` in your +shell environment. + +## Enabling GPU Support with JAX + +For any software stack (using conda compilers, NVHPC, etc), you can [install +JAX using the official instructions +here](https://github.com/google/jax#installation). You can enable JAX code by +setting `TOAST_GPU_JAX=1` in your shell environment. + diff --git a/platforms/cmbenv-gcc.sh b/platforms/cmbenv-gcc.sh new file mode 100755 index 000000000..71ab3852b --- /dev/null +++ b/platforms/cmbenv-gcc.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +cmake \ + -DCMAKE_C_COMPILER="gcc" \ + -DCMAKE_CXX_COMPILER="g++" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DAATM_ROOT="${CMBENV_AUX_ROOT}" \ + -DFFTW_ROOT="${CMBENV_AUX_ROOT}" \ + -DBLAS_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DLAPACK_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" \ + ${opts} \ + .. diff --git a/platforms/cmbenv-rocm-dbg.sh b/platforms/cmbenv-rocm-dbg.sh new file mode 100755 index 000000000..e2aefbb42 --- /dev/null +++ b/platforms/cmbenv-rocm-dbg.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +cmake \ + -DCMAKE_C_COMPILER="amdclang" \ + -DCMAKE_CXX_COMPILER="amdclang++" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_FLAGS="-O0 -g -fPIC -Wno-error=implicit-function-declaration" \ + -DCMAKE_CXX_FLAGS="-O0 -g -fPIC" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="\ + -gline-tables-only \ + -fopenmp-target-debug=3 \ + -fopenmp-targets=amdgcn-amd-amdhsa \ + -Xopenmp-target=amdgcn-amd-amdhsa \ + -march=gfx1030 \ + " \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DAATM_ROOT="${CMBENV_AUX_ROOT}" \ + -DFFTW_ROOT="${CMBENV_AUX_ROOT}" \ + -DBLAS_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DLAPACK_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" \ + ${opts} \ + .. diff --git a/platforms/cmbenv-rocm.sh b/platforms/cmbenv-rocm.sh new file mode 100755 index 000000000..218af73d1 --- /dev/null +++ b/platforms/cmbenv-rocm.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +cmake \ + -DCMAKE_C_COMPILER="amdclang" \ + -DCMAKE_CXX_COMPILER="amdclang++" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC -Wno-error=implicit-function-declaration" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="\ + -fopenmp-targets=amdgcn-amd-amdhsa \ + -Xopenmp-target=amdgcn-amd-amdhsa \ + -march=gfx1030 \ + " \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DAATM_ROOT="${CMBENV_AUX_ROOT}" \ + -DFFTW_ROOT="${CMBENV_AUX_ROOT}" \ + -DBLAS_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DLAPACK_LIBRARIES=${CMBENV_AUX_ROOT}/lib/libopenblas.so \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" \ + ${opts} \ + .. diff --git a/platforms/conda.sh b/platforms/conda.sh new file mode 100755 index 000000000..351a9cd90 --- /dev/null +++ b/platforms/conda.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +set -e + +INSTALL=$1 + +if [ "x${CONDA_PREFIX}" = "x" ]; then + echo "You must activate a conda environment before using this script." + exit 1 +fi + +if [ "x${CONDA_TOOLCHAIN_HOST}" = "x" ]; then + echo "Your conda environment does not contain compilers. Run conda_dev_setup.sh first." + exit 1 +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +PREFIX="${CONDA_PREFIX}" +PYTHON="${PREFIX}/bin/python" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +shext="so" +if [[ ${CONDA_TOOLCHAIN_HOST} =~ .*darwin.* ]]; then + export TOAST_BUILD_CMAKE_OSX_SYSROOT="${CONDA_BUILD_SYSROOT}" + shext="dylib" +fi + +export TOAST_BUILD_CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} +export TOAST_BUILD_CMAKE_PLATFORM_FLAGS=${CMAKE_PLATFORM_FLAGS} +export TOAST_BUILD_CMAKE_C_COMPILER="${CC}" +export TOAST_BUILD_CMAKE_CXX_COMPILER="${CXX}" +export TOAST_BUILD_CMAKE_C_FLAGS="-O3 -g -fPIC" +export TOAST_BUILD_CMAKE_CXX_FLAGS="-O3 -g -fPIC" +export TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=1 +export TOAST_BUILD_CMAKE_INSTALL_PREFIX="${PREFIX}" +export TOAST_BUILD_CMAKE_PREFIX_PATH="${PREFIX}" +export TOAST_BUILD_FFTW_ROOT="${PREFIX}" +export TOAST_BUILD_AATM_ROOT="${PREFIX}" +export TOAST_BUILD_BLAS_LIBRARIES="${LIBDIR}/libblas.${shext}" +export TOAST_BUILD_LAPACK_LIBRARIES="${LIBDIR}/liblapack.${shext}" +export TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" +export TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" + +# Ensure that stale build products are removed +rm -rf "${topdir}/build" + +if [ -z "${INSTALL}" ]; then + pip install -vvv . +else + pip install -vvv --prefix "${INSTALL}" . +fi diff --git a/platforms/conda_dev.sh b/platforms/conda_dev.sh new file mode 100755 index 000000000..f6f6ed69f --- /dev/null +++ b/platforms/conda_dev.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip), but uses the +# conda compilers and other dependencies provided by conda. It is +# useful for building toast in parallel repeatedly for debugging +# in situations where clean un-install is not a concern. + +set -e + +opts="$@" + +if [ "x${CONDA_PREFIX}" = "x" ]; then + echo "You must activate a conda environment before using this script." + exit 1 +fi + +if [ "x${CONDA_TOOLCHAIN_HOST}" = "x" ]; then + echo "Your conda environment does not contain compilers. Run conda_dev_setup.sh first." + exit 1 +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +PREFIX="${CONDA_PREFIX}" +PYTHON="${PREFIX}/bin/python" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +CMAKE_PLATFORM_FLAGS="" +shext="so" +if [[ ${CONDA_TOOLCHAIN_HOST} =~ .*darwin.* ]]; then + CMAKE_PLATFORM_FLAGS+=(-DCMAKE_OSX_SYSROOT="${CONDA_BUILD_SYSROOT}") + shext="dylib" +fi + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" ${CMAKE_PLATFORM_FLAGS} \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${LIBDIR}/libblas.${shext}" \ + -DLAPACK_LIBRARIES="${LIBDIR}/liblapack.${shext}" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} "${topdir}" diff --git a/platforms/conda_dev_nvhpc.sh b/platforms/conda_dev_nvhpc.sh new file mode 100755 index 000000000..679224d19 --- /dev/null +++ b/platforms/conda_dev_nvhpc.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip), but uses the +# conda compilers and other dependencies provided by conda. It is +# useful for building toast in parallel repeatedly for debugging +# in situations where clean un-install is not a concern. + +set -e + +opts="$@" + +if [ "x${CONDA_PREFIX}" = "x" ]; then + echo "You must activate a conda environment before using this script." + exit 1 +fi + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the sidecar +# directory of compiled packages. +ext_path="${CONDA_PREFIX}_ext" +if [ ! -d "${ext_path}" ]; then + echo "External package directory '${ext_path}' does not exist." + echo "Did you use conda_dev_setup_nvhpc.sh to create the env?" + exit 1 +fi +source "${topdir}/packaging/conda/load_conda_external.sh" +prepend_ext_env "PATH" "${ext_path}/bin" +prepend_ext_env "CPATH" "${ext_path}/include" +prepend_ext_env "LIBRARY_PATH" "${ext_path}/lib" +prepend_ext_env "LD_LIBRARY_PATH" "${ext_path}/lib" +prepend_ext_env "PKG_CONFIG_PATH" "${ext_path}/lib/pkgconfig" + +PREFIX="${ext_path}" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11" +export OMPFLAGS="-fopenmp" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="nvc" \ + -DCMAKE_CXX_COMPILER="nvc++" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread -std=c++11" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${CONDA_PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${nvlibs}/libblas.so;${nvlibs}/libnvf.so" \ + -DLAPACK_LIBRARIES="${nvlibs}/liblapack.so;${nvlibs}/libnvf.so" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} diff --git a/platforms/conda_dev_setup.sh b/platforms/conda_dev_setup.sh new file mode 100755 index 000000000..0c89e9917 --- /dev/null +++ b/platforms/conda_dev_setup.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# If you would like to create your environments in an alternate +# directory, first load the base environment and add the +# alternate location to your conda config: +# +# conda config --append envs_dirs path/to/envs +# +# Then run this script with the full location: +# +# ./platforms/conda_dev_setup.sh path/to/envs/my_env +# +# and then when activating the environment you can reference +# it with just "my_env". +# +# NOTE: by default, the full path to the conda env will be +# displayed in the shell prompt. To avoid this, edit ~/.condarc +# and add this line: +# +# env_prompt: '({name}) ' +# +# Now only the basename of the environment will show up. + +envname=$1 +pyversion=$2 +optional=$3 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +condapkgdir=$(dirname "${scriptdir}")/packaging/conda + +conda_exe=$(which conda) +if [ "x${conda_exe}" = "x" ]; then + echo "No conda executable found" + exit 1 +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The named environment will be activated (and created if needed)" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +eval "${condapkgdir}/install_deps_conda.sh" "${envname}" ${pyversion} ${optional} diff --git a/platforms/conda_dev_setup_nvhpc.sh b/platforms/conda_dev_setup_nvhpc.sh new file mode 100755 index 000000000..e317c5f13 --- /dev/null +++ b/platforms/conda_dev_setup_nvhpc.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# This script assumes you have a conda base environment loaded AND +# you have the NVHPC SDK loaded (through a modulefile or similar). +# Note that to build mpi4py with a custom MPI compiler, you should +# load the nvhpc-nompi module and set the MPICC environment variable +# before running this script. + +envname=$1 +pyversion=$2 +optional=$3 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +condapkgdir=$(dirname "${scriptdir}")/packaging/conda + +conda_exe=$(which conda) +if [ "x${conda_exe}" = "x" ]; then + echo "No conda executable found" + exit 1 +fi + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The named environment will be activated (and created if needed)" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11" +export OMPFLAGS="-fopenmp" +export FCLIBS="-lnvf -lrt" +export BLAS_LIBRARIES="-L${nvlibs} -lblas -lnvf -mp -lrt" +export LAPACK_LIBRARIES="-L${nvlibs} -llapack -lnvf -mp -lrt" + +eval "${condapkgdir}/install_deps_conda_external.sh" "${envname}" ${pyversion} ${optional} diff --git a/platforms/cori-gcc.sh b/platforms/cori-gcc.sh deleted file mode 100755 index 5e0a82a4f..000000000 --- a/platforms/cori-gcc.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -opts="$@" - -cmake \ - -DCMAKE_C_COMPILER="gcc" \ - -DCMAKE_CXX_COMPILER="g++" \ - -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ - -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ - -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ - -DMKL_DISABLED=TRUE \ - -DBLAS_LIBRARIES=$CMBENV_AUX_ROOT/lib/libopenblas.so \ - -DLAPACK_LIBRARIES=$CMBENV_AUX_ROOT/lib/libopenblas.so \ - -DFFTW_ROOT=$CMBENV_AUX_ROOT \ - -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ - -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" \ - ${opts} \ - .. diff --git a/platforms/cori-intel.sh b/platforms/cori-intel.sh deleted file mode 100755 index 644808251..000000000 --- a/platforms/cori-intel.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -opts="$@" - -cmake \ - -DCMAKE_C_COMPILER="icc" \ - -DCMAKE_CXX_COMPILER="icpc" \ - -DCMAKE_C_FLAGS="-O3 -g -fPIC -xcore-avx2 -axmic-avx512 -pthread" \ - -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -xcore-avx2 -axmic-avx512 -pthread" \ - -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ - -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ - -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" \ - ${opts} \ - .. diff --git a/platforms/install_test_runner.sh b/platforms/install_test_runner.sh deleted file mode 100755 index b44ebc8ea..000000000 --- a/platforms/install_test_runner.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# This script is for a complete build and install to /usr/local inside a -# docker container. It is used when running CI unit tests. - -set -e - -# Get the absolute path to the source tree -pushd $(dirname $(dirname $0)) >/dev/null 2>&1 -toastdir=$(pwd -P) -popd >/dev/null 2>&1 - -mkdir build -pushd build >/dev/null 2>&1 - -cmake \ - -DCMAKE_C_COMPILER="gcc" \ - -DCMAKE_CXX_COMPILER="g++" \ - -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ - -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ - -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ - -DCMAKE_INSTALL_PREFIX=/usr/local \ - "${toastdir}" - -make -j 2 install - -popd >/dev/null 2>&1 diff --git a/platforms/install_test_runner_linux.sh b/platforms/install_test_runner_linux.sh new file mode 100755 index 000000000..4fa5a9423 --- /dev/null +++ b/platforms/install_test_runner_linux.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# This script is for a complete build and install to /usr/local inside a +# docker container. It is used when running CI unit tests. + +set -e + +# Temporary workaround- update pshmem pip package until upstream container +# has new release. +# python3 -m pip install --upgrade pshmem + +# Get the absolute path to the source tree +pushd $(dirname $(dirname $0)) >/dev/null 2>&1 +toastdir=$(pwd -P) +popd >/dev/null 2>&1 + +mkdir build +pushd build >/dev/null 2>&1 + +cmake \ + -DCMAKE_C_COMPILER="gcc" \ + -DCMAKE_CXX_COMPILER="g++" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + "${toastdir}" + +make -j 2 install + +# Copy additional test scripts +cp ${toastdir}/etc/test_mpi_exit_code* /usr/local/bin/ + +popd >/dev/null 2>&1 diff --git a/platforms/linux-gcc-dbg.sh b/platforms/linux-gcc-dbg.sh new file mode 100755 index 000000000..bf15ae016 --- /dev/null +++ b/platforms/linux-gcc-dbg.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +cmake \ + -DCMAKE_C_COMPILER="gcc" \ + -DCMAKE_CXX_COMPILER="g++" \ + -DCMAKE_C_FLAGS="-O0 -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="-O0 -g -fPIC -pthread" \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + ${opts} \ + .. diff --git a/platforms/linux-gcc.sh b/platforms/linux-gcc.sh index 9c793fe2c..80397d413 100755 --- a/platforms/linux-gcc.sh +++ b/platforms/linux-gcc.sh @@ -10,7 +10,6 @@ cmake \ -DCMAKE_CXX_COMPILER="g++" \ -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread" \ -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ - -DMKL_DISABLED=TRUE \ -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ ${opts} \ diff --git a/platforms/linux-gcc12-nvptx-dbg.sh b/platforms/linux-gcc12-nvptx-dbg.sh new file mode 100755 index 000000000..835ea979e --- /dev/null +++ b/platforms/linux-gcc12-nvptx-dbg.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# NOTE: This assumes gcc >= 12.1.0 + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +cmake \ + -DCMAKE_BUILD_TYPE="Debug" \ + -DCMAKE_C_COMPILER="gcc-12" \ + -DCMAKE_CXX_COMPILER="g++-12" \ + -DCMAKE_C_FLAGS="-O0 -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="-O0 -g -fPIC -pthread -std=c++11 -fcf-protection=none -fno-stack-protector" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="\ + -foffload=nvptx-none \ + -foffload-options=-Wa,-m,sm_80 \ + -foffload-options=-misa=sm_80 \ + -foffload-options=-lm \ + -foffload-options=-latomic \ + " \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + ${opts} \ + .. + + + diff --git a/platforms/linux-intel.sh b/platforms/linux-intel.sh index 5e3774c27..e0d6ba9bd 100755 --- a/platforms/linux-intel.sh +++ b/platforms/linux-intel.sh @@ -12,5 +12,6 @@ cmake \ -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread" \ -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DUSE_MKL=TRUE \ ${opts} \ .. diff --git a/platforms/linux-llvm.sh b/platforms/linux-llvm.sh new file mode 100755 index 000000000..b86238063 --- /dev/null +++ b/platforms/linux-llvm.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# This assumes you have created a virtualenv and installed toast +# dependencies (e.g. with wheels/install_deps_linux.sh) into that virtual +# env. This assumes installation of llvm-18 from LLVM apt sources. + +venv_path=$(dirname $(dirname $(which python3))) + +export LD_LIBRARY_PATH="${venv_path}/lib" + +cmake \ + -DCMAKE_C_COMPILER="clang-18" \ + -DCMAKE_CXX_COMPILER="clang++-18" \ + -DCMAKE_C_FLAGS="-O3 -g -fPIC -pthread -I${venv_path}/include" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -pthread -std=c++11 -stdlib=libc++ -I${venv_path}/include" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="-fopenmp -fopenmp-targets=nvptx64 -fopenmp-target-debug=3 --offload-arch=sm_86 -Wl,-lomp,-lomptarget,-lomptarget.rtl.cuda" \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCMAKE_LIBRARY_PATH="${venv_path}/lib" \ + -DBLAS_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm -lgfortran" \ + -DLAPACK_LIBRARIES="-L${venv_path}/lib -lopenblas -fopenmp -lm -lgfortran" \ + -DAATM_ROOT="${venv_path}" \ + -DFFTW_ROOT="${venv_path}" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${venv_path}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${venv_path}/lib" \ + -DTOAST_STATIC_DEPS=ON \ + -DCMAKE_INSTALL_PREFIX="${venv_path}" \ + .. + diff --git a/platforms/old_test_runner_macos.sh b/platforms/old_test_runner_macos.sh new file mode 100755 index 000000000..3de9dd1b5 --- /dev/null +++ b/platforms/old_test_runner_macos.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# This script is for a complete build and install to /usr/local inside a +# docker container. It is used when running CI unit tests. + +set -e + +# Get the absolute path to the source tree +pushd $(dirname $(dirname $0)) >/dev/null 2>&1 +toastdir=$(pwd -P) +popd >/dev/null 2>&1 + +# Install minimal dependencies +eval ${toastdir}/wheels/install_deps_osx.sh macosx_x86_64 yes + +# Install toast + +pushd ${toastdir} >/dev/null 2>&1 + +export TOAST_BUILD_CMAKE_C_COMPILER=clang +export TOAST_BUILD_CMAKE_CXX_COMPILER=clang++ +export TOAST_BUILD_BLA_VENDOR='Apple' +export TOAST_BUILD_DISABLE_OPENMP=1 +export TOAST_BUILD_CMAKE_C_FLAGS="-O2 -g -fPIC" +export TOAST_BUILD_CMAKE_CXX_FLAGS="-O2 -g -fPIC -std=c++11 -stdlib=libc++" +export TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=ON +python3 -m pip -vvv install . + +popd >/dev/null 2>&1 diff --git a/platforms/osx_homebrew.sh b/platforms/osx_homebrew.sh index c170ad6ed..254015a29 100755 --- a/platforms/osx_homebrew.sh +++ b/platforms/osx_homebrew.sh @@ -14,7 +14,10 @@ cmake \ -DCMAKE_C_COMPILER="clang" \ -DCMAKE_CXX_COMPILER="clang++" \ -DCMAKE_C_FLAGS="-O3 -g -fPIC" \ - -DCMAKE_CXX_FLAGS="-O3 -g -fPIC" \ + -DCMAKE_CXX_FLAGS="-O3 -g -fPIC -std=c++11 -stdlib=libc++" \ + -DDISABLE_OPENMP=1 \ + -DBLA_VENDOR="Apple" \ + -DFFTW_ROOT=$(brew --prefix) \ -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ ${opts} \ diff --git a/platforms/perlmutter-cmbenv-nvhpc.sh b/platforms/perlmutter-cmbenv-nvhpc.sh new file mode 100755 index 000000000..b1fdf924b --- /dev/null +++ b/platforms/perlmutter-cmbenv-nvhpc.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Pass extra cmake options to this script, including +# things like -DCMAKE_INSTALL_PREFIX=/path/to/install, etc. + +opts="$@" + +if [ "x${CMBENV_AUX_ROOT}" = "x" ]; then + echo "You must activate a cmbenv environment before using this script." + exit 1 +fi + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug + oflags="-O0" +else + CMAKE_BUILD_TYPE=Release + oflags="-O3" +fi + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="nvc" \ + -DCMAKE_CXX_COMPILER="nvc++" \ + -DCMAKE_C_FLAGS="${oflags} -g -fPIC -pthread" \ + -DCMAKE_CXX_FLAGS="${oflags} -g -fPIC -pthread -std=c++11" \ + -DOPENMP_TARGET_FLAGS="-Minfo=mp -gpu=cc80" \ + -DPYTHON_EXECUTABLE:FILEPATH=$(which python3) \ + -DUSE_OPENMP_TARGET=TRUE \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DFFTW_ROOT="${CMBENV_AUX_ROOT}" \ + -DAATM_ROOT="${CMBENV_AUX_ROOT}" \ + -DDISABLE_FLAC=1 \ + -DBLAS_LIBRARIES="-L${NVHPC_ROOT}/compilers/lib -lblas -lnvf -mp -lrt" \ + -DLAPACK_LIBRARIES="-L${NVHPC_ROOT}/compilers/lib -llapack -lnvf -mp -lrt" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${CMBENV_AUX_ROOT}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${CMBENV_AUX_ROOT}/lib" ${opts} \ + .. + diff --git a/platforms/perlmutter-llvm.sh b/platforms/perlmutter-llvm.sh new file mode 100755 index 000000000..c253a2f9f --- /dev/null +++ b/platforms/perlmutter-llvm.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +# No suffix on perlmutter +suf="" + +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" +INCDIR="${PREFIX}/include" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -I${INCDIR}" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="-fopenmp -fopenmp-targets=nvptx64 -fopenmp-target-debug=3 --offload-arch=sm_80 -Wl,-lomp,-lomptarget,-lomptarget.rtl.cuda" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${LIBDIR}/libopenblas.so" \ + -DLAPACK_LIBRARIES="${LIBDIR}/libopenblas.so" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} diff --git a/platforms/perlmutter-llvm_setup.sh b/platforms/perlmutter-llvm_setup.sh new file mode 100755 index 000000000..00416337f --- /dev/null +++ b/platforms/perlmutter-llvm_setup.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND an installation +# of LLVM with OpenMP target offload support. If the second option +# to this script is "yes", you must set the MPICC variable to your +# MPI compiler for building mpi4py. + +envname=$1 +optional=$2 + +if [ "x${optional}" != "xyes" ]; then + optional=no +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +# No suffix names on perlmutter +suf="" + +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11" +export OMPFLAGS="-fopenmp" +export FCLIBS="-lgfortran" +# Note: LD_LIBRARY_PATH already setup + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} no diff --git a/platforms/perlmutter-nvhpc.sh b/platforms/perlmutter-nvhpc.sh new file mode 100755 index 000000000..6f9b99288 --- /dev/null +++ b/platforms/perlmutter-nvhpc.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" +INCDIR="${PREFIX}/include" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror -I${INCDIR}" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="-L${nvlibs} -lblas -lnvf -mp -lrt" \ + -DLAPACK_LIBRARIES="-L${nvlibs} -llapack -lnvf -mp -lrt" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} + diff --git a/platforms/perlmutter-nvhpc_setup.sh b/platforms/perlmutter-nvhpc_setup.sh new file mode 100755 index 000000000..8a6feece0 --- /dev/null +++ b/platforms/perlmutter-nvhpc_setup.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND +# you have the NVHPC SDK loaded (through a modulefile or similar). +# Note that to build mpi4py with a custom MPI compiler, you should +# load the nvhpc-nompi module and set the MPICC environment variable +# before running this script. Otherwise load the normal nvhpc module +# and use the MPI that ships with NVHPC. + +envname=$1 +optional=$2 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror" +export OMPFLAGS="-mp" +export FCLIBS="-lnvf -lrt" +export BLAS_LIBRARIES="-L${nvlibs} -lblas -lnvf -mp -lrt" +export LAPACK_LIBRARIES="-L${nvlibs} -llapack -lnvf -mp -lrt" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} no diff --git a/platforms/venv_dev_gcc.sh b/platforms/venv_dev_gcc.sh new file mode 100755 index 000000000..1e539d6d6 --- /dev/null +++ b/platforms/venv_dev_gcc.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the GNU +# compilers + +set -e + +opts="$@" + +if [ "x$(which g++)" = "x" ]; then + echo "The g++ compiler is not in your PATH" + exit 1 +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=gcc +export CXX=g++ +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DTOAST_STATIC_DEPS=ON \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${LIBDIR}/libopenblas.a" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} .. diff --git a/platforms/venv_dev_llvm.sh b/platforms/venv_dev_llvm.sh new file mode 100755 index 000000000..e60e1e3ef --- /dev/null +++ b/platforms/venv_dev_llvm.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +suf="-18" +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" +INCDIR="${PREFIX}/include" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -stdlib=libc++ -I${INCDIR}" + +export LD_LIBRARY_PATH="/usr/lib/llvm-18/lib:/usr/lib/gcc/x86_64-linux-gnu/11:${LIBDIR}" +export LIBRARY_PATH="/usr/lib/llvm-18/lib:/usr/lib/gcc/x86_64-linux-gnu/11:${LIBDIR}" + +# # export CMAKE_MODULE_LINKER_FLAGS="-L/usr/lib/llvm-18/lib -stdlib=libc++ " +# export LINK_OPTIONS="-stdlib=libc++" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="-fopenmp -fopenmp-targets=nvptx64 -fopenmp-target-debug=3 --offload-arch=sm_86 -Wl,-lomp,-lomptarget,-lomptarget.rtl.cuda" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${LIBDIR}/libopenblas.so;/usr/lib/gcc/x86_64-linux-gnu/11/libgfortran.so" \ + -DLAPACK_LIBRARIES="${LIBDIR}/libopenblas.so;/usr/lib/gcc/x86_64-linux-gnu/11/libgfortran.so" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} diff --git a/platforms/venv_dev_llvm_static.sh b/platforms/venv_dev_llvm_static.sh new file mode 100755 index 000000000..96ab1d525 --- /dev/null +++ b/platforms/venv_dev_llvm_static.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +suf="-18" +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" +INCDIR="${PREFIX}/include" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -stdlib=libc++ -I${INCDIR}" + +export LD_LIBRARY_PATH="/usr/lib/llvm-18/lib:${LIBDIR}" +export LIBRARY_PATH="/usr/lib/llvm-18/lib:${LIBDIR}" + +# # export CMAKE_MODULE_LINKER_FLAGS="-L/usr/lib/llvm-18/lib -stdlib=libc++ " +# export LINK_OPTIONS="-stdlib=libc++" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DTOAST_STATIC_DEPS=ON \ + -DUSE_OPENMP_TARGET=TRUE \ + -DOPENMP_TARGET_FLAGS="-fopenmp -fopenmp-targets=nvptx64 -fopenmp-target-debug=3 --offload-arch=sm_86 -Wl,-lomp,-lomptarget,-lomptarget.rtl.cuda" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${LIBDIR}/libopenblas.a;/usr/lib/gcc/x86_64-linux-gnu/11/libgfortran.a" \ + -DLAPACK_LIBRARIES="${LIBDIR}/libopenblas.a;/usr/lib/gcc/x86_64-linux-gnu/11/libgfortran.a" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} diff --git a/platforms/venv_dev_nvhpc.sh b/platforms/venv_dev_nvhpc.sh new file mode 100755 index 000000000..9a9547e42 --- /dev/null +++ b/platforms/venv_dev_nvhpc.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="-L${nvlibs} -lblas -lnvf -mp -lrt" \ + -DLAPACK_LIBRARIES="-L${nvlibs} -llapack -lnvf -mp -lrt" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} + +# -DBLAS_LIBRARIES="${nvlibs}/libblas.so;${nvlibs}/libnvf.so;-lrt" \ +# -DLAPACK_LIBRARIES="${nvlibs}/liblapack.so;${nvlibs}/libnvf.so;-lrt" \ diff --git a/platforms/venv_dev_nvhpc_static.sh b/platforms/venv_dev_nvhpc_static.sh new file mode 100755 index 000000000..f49d21a3b --- /dev/null +++ b/platforms/venv_dev_nvhpc_static.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# This configures toast using cmake directly (not pip) and the NVHPC +# compilers + +set -e + +opts="$@" + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +# Use the helper shell functions to load the venv path +# into the library search paths +venv_path=$(dirname $(dirname $(which python3))) + +PREFIX="${venv_path}" +LIBDIR="${PREFIX}/lib" + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror" + +cmake \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_FLAGS="${CFLAGS}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DTOAST_STATIC_DEPS=ON \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DFFTW_ROOT="${PREFIX}" \ + -DAATM_ROOT="${PREFIX}" \ + -DFLAC_ROOT="${PREFIX}" \ + -DBLAS_LIBRARIES="${nvlibs}/libblas_lp64.a;${nvlibs}/libnvf.a" \ + -DLAPACK_LIBRARIES="${nvlibs}/liblapack_lp64.a" \ + -DSUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" \ + -DSUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" \ + ${opts} ${topdir} diff --git a/platforms/venv_dev_setup_gcc.sh b/platforms/venv_dev_setup_gcc.sh new file mode 100755 index 000000000..498fa5c13 --- /dev/null +++ b/platforms/venv_dev_setup_gcc.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND you have a working +# gcc available. Note that to build mpi4py with a custom MPI compiler, +# you should have the MPICC environment variable set to the compiler +# before running this script. + +envname=$1 +optional=$2 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +if [ "x$(which g++)" = "x" ]; then + echo "The GNU compilers are not in your PATH" + exit 1 +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=gcc +export CXX=g++ +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11" +export OMPFLAGS="-fopenmp" +export FCLIBS="-lgfortran" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} diff --git a/platforms/venv_dev_setup_llvm.sh b/platforms/venv_dev_setup_llvm.sh new file mode 100755 index 000000000..a3b56148c --- /dev/null +++ b/platforms/venv_dev_setup_llvm.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND an installation +# of LLVM with OpenMP target offload support. If the second option +# to this script is "yes", you must set the MPICC variable to your +# MPI compiler for building mpi4py. + +envname=$1 +optional=$2 + +if [ "x${optional}" != "xyes" ]; then + optional=no +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +suf="-18" +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -stdlib=libc++" +export OMPFLAGS="-fopenmp" +export FCLIBS="-L/usr/lib/gcc/x86_64-linux-gnu/11 -lgfortran" + +export LD_LIBRARY_PATH="/usr/lib/llvm-18/lib:/usr/lib/gcc/x86_64-linux-gnu/11:${envname}/lib" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} no diff --git a/platforms/venv_dev_setup_llvm_static.sh b/platforms/venv_dev_setup_llvm_static.sh new file mode 100755 index 000000000..e7bf63274 --- /dev/null +++ b/platforms/venv_dev_setup_llvm_static.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND an installation +# of LLVM with OpenMP target offload support. If the second option +# to this script is "yes", you must set the MPICC variable to your +# MPI compiler for building mpi4py. + +envname=$1 +optional=$2 + +if [ "x${optional}" != "xyes" ]; then + optional=no +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +suf="-18" +if [ "x$(which clang++${suf})" = "x" ]; then + echo "The clang++${suf} compiler is not in your PATH, trying clang++" + if [ "x$(which clang++)" = "x" ]; then + echo "No clang++ found" + exit 1 + else + suf="" + fi +fi + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=clang${suf} +export CXX=clang++${suf} +export FC=gfortran +export CFLAGS="-O3 -g -fPIC -pthread" +export FCFLAGS="-O3 -g -fPIC -pthread" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -stdlib=libc++" +export OMPFLAGS="-fopenmp" +export FCLIBS="-L/usr/lib/gcc/x86_64-linux-gnu/11 -lgfortran" + +export LD_LIBRARY_PATH="/usr/lib/llvm-18/lib:/usr/lib/gcc/x86_64-linux-gnu/11:${envname}/lib" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} yes diff --git a/platforms/venv_dev_setup_nvhpc.sh b/platforms/venv_dev_setup_nvhpc.sh new file mode 100755 index 000000000..8a6feece0 --- /dev/null +++ b/platforms/venv_dev_setup_nvhpc.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND +# you have the NVHPC SDK loaded (through a modulefile or similar). +# Note that to build mpi4py with a custom MPI compiler, you should +# load the nvhpc-nompi module and set the MPICC environment variable +# before running this script. Otherwise load the normal nvhpc module +# and use the MPI that ships with NVHPC. + +envname=$1 +optional=$2 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror" +export OMPFLAGS="-mp" +export FCLIBS="-lnvf -lrt" +export BLAS_LIBRARIES="-L${nvlibs} -lblas -lnvf -mp -lrt" +export LAPACK_LIBRARIES="-L${nvlibs} -llapack -lnvf -mp -lrt" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} no diff --git a/platforms/venv_dev_setup_nvhpc_static.sh b/platforms/venv_dev_setup_nvhpc_static.sh new file mode 100755 index 000000000..f29451ba6 --- /dev/null +++ b/platforms/venv_dev_setup_nvhpc_static.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This script assumes you have a python3 loaded AND +# you have the NVHPC SDK loaded (through a modulefile or similar). +# Note that to build mpi4py with a custom MPI compiler, you should +# load the nvhpc-nompi module and set the MPICC environment variable +# before running this script. Otherwise load the normal nvhpc module +# and use the MPI that ships with NVHPC. + +envname=$1 +optional=$2 + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 + +# Location of build helper tools +venvpkgdir=$(dirname "${scriptdir}")/packaging/venv + +if [ "x$(which nvc++)" = "x" ]; then + echo "The nvc++ compiler is not in your PATH" + exit 1 +fi +nvlibs=$(dirname $(dirname $(which nvc++)))/lib + +usage () { + echo "" + echo "Usage: $0 " + echo "" + echo "The virtualenv will be created and / or activated" + echo "" +} + +if [ "x${envname}" = "x" ]; then + usage + exit 1 +fi + +# Set our compiler flags +export CC=nvc +export CXX=nvc++ +export FC=nvfortran +export CFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export FCFLAGS="-O3 -g -fPIC -pthread -noswitcherror" +export CXXFLAGS="-O3 -g -fPIC -pthread -std=c++11 -noswitcherror" +export OMPFLAGS="-mp" +export FCLIBS="${nvlibs}/libnvf.a -lrt" +export BLAS_LIBRARIES="${nvlibs}/libblas_lp.a ${nvlibs}/libnvf.a -mp -lrt" +export LAPACK_LIBRARIES="${nvlibs}/liblapack_lp.a ${nvlibs}/libnvf.a -mp -lrt" + +eval "${venvpkgdir}/install_deps_venv.sh" "${envname}" ${optional} yes diff --git a/platforms/wheel.sh b/platforms/wheel.sh new file mode 100755 index 000000000..c435d7b53 --- /dev/null +++ b/platforms/wheel.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -e + +PYTHON=$(which python3) +PREFIX=$(dirname $(dirname "${PYTHON}")) +LIBDIR="${PREFIX}/lib" + +echo "Using Python '${PYTHON}'" +echo "Installing to '${PREFIX}'" + +os=linux +if [ "x$(uname)" != "xLinux" ]; then + os=darwin +fi + +# Location of this script +pushd $(dirname $0) >/dev/null 2>&1 +scriptdir=$(pwd) +popd >/dev/null 2>&1 +topdir=$(dirname "${scriptdir}") + +if [ "x${DEBUG}" = "x1" ]; then + CMAKE_BUILD_TYPE=Debug +else + CMAKE_BUILD_TYPE=Release +fi + +shext="so" +if [ "${os}" = "darwin" ]; then + shext="dylib" +fi + +if [ "x${CC}" = "x" ]; then + echo "Set the CC variable to desired C compiler" + exit 1 +fi + +if [ "x${CXX}" = "x" ]; then + echo "Set the CXX variable to desired C++ compiler" + exit 1 +fi + +export TOAST_BUILD_CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} +export TOAST_BUILD_CMAKE_C_COMPILER="${CC}" +export TOAST_BUILD_CMAKE_CXX_COMPILER="${CXX}" +export TOAST_BUILD_CMAKE_C_FLAGS="-O3 -g -fPIC" +export TOAST_BUILD_CMAKE_CXX_FLAGS="-O3 -g -fPIC" +export TOAST_BUILD_CMAKE_VERBOSE_MAKEFILE=1 +export TOAST_BUILD_CMAKE_INSTALL_PREFIX="${PREFIX}" +export TOAST_BUILD_CMAKE_PREFIX_PATH="${PREFIX}" +export TOAST_BUILD_FFTW_ROOT="${PREFIX}" +export TOAST_BUILD_AATM_ROOT="${PREFIX}" +export TOAST_BUILD_BLAS_LIBRARIES="${LIBDIR}/libblas.${shext}" +export TOAST_BUILD_LAPACK_LIBRARIES="${LIBDIR}/liblapack.${shext}" +export TOAST_BUILD_SUITESPARSE_INCLUDE_DIR_HINTS="${PREFIX}/include" +export TOAST_BUILD_SUITESPARSE_LIBRARY_DIR_HINTS="${LIBDIR}" + +pushd "${topdir}" >/dev/null 2>&1 + +# Now build a wheel +rm -rf build +python3 setup.py clean +python3 -m pip wheel --wheel-dir=build/temp_wheels --no-deps -vvv . + +input_wheel=$(ls ${topdir}/build/temp_wheels/*.whl) +wheel_file=$(basename ${input_wheel}) + +# Repair it +if [ "${os}" = "darwin" ]; then + delocate-listdeps ${input_wheel} \ + && delocate-wheel -w "${topdir}/wheelhouse" ${input_wheel} +else + auditwheel show ${input_wheel} \ + && auditwheel repair ${input_wheel} +fi + +# Install it +python3 -m pip install "${topdir}/wheelhouse/${wheel_file}" + +popd >/dev/null 2>&1 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a4fac2605 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +# Minimal config to ensure that setuptools is available +# before loading setup.py. We have extensive build and +# version customization in setup.py that we intentionally +# do not put in this file. +[build-system] +requires = ["setuptools", "wheel"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..2cbbb75db --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +--index-url https://pypi.python.org/simple/ + +# By default, use our abstract dependencies in setup.py for the +# concrete dependencies from PyPI. +. diff --git a/setup.py b/setup.py index 82ce375b5..108daa4b0 100644 --- a/setup.py +++ b/setup.py @@ -17,8 +17,8 @@ def find_compilers(): cc = None cxx = None # If we have mpi4py, then get the MPI compilers that were used to build that. - # Then get the serial compilers used by the MPI wrappers. Otherwise, just the - # normal distutils compilers. + # Then get the serial compilers used by the MPI wrappers. Otherwise return + # None and later let CMake guess the compilers. try: from mpi4py import MPI import mpi4py @@ -32,21 +32,21 @@ def find_compilers(): mpicc_com = subprocess.check_output( "{} -show".format(mpicc), shell=True, universal_newlines=True ) - except CalledProcessError: + except subprocess.CalledProcessError: # Cannot run the MPI C compiler, give up raise ImportError try: mpicxx_com = subprocess.check_output( "{} -show".format(mpicxx), shell=True, universal_newlines=True ) - except CalledProcessError: + except subprocess.CalledProcessError: # Cannot run the MPI C++ compiler, give up raise ImportError # Extract the serial compilers cc = mpicc_com.split()[0] cxx = mpicxx_com.split()[0] - except ImportError: + except (ImportError, KeyError): pass return (cc, cxx) @@ -73,11 +73,20 @@ def get_version(): mat = re.match(r'.*RELEASE_VERSION = "(.*)".*', line) if mat is not None: rel_ver = mat.group(1) - if (git_ver is not None) and (git_ver != ""): + if ( + "READTHEDOCS" in os.environ + or "CI" in os.environ + or "CIBUILDWHEEL" in os.environ + ): + # We are running inside build infrastructure that requires a PEP440 version + # and may be using a shallow clone, so the git version is malformed. Always + # use the release version in this case. + ver = rel_ver + elif (git_ver is not None) and (git_ver != ""): ver = git_ver else: ver = rel_ver - except CalledProcessError: + except subprocess.CalledProcessError: raise RuntimeError("Cannot generate version!") return ver @@ -104,8 +113,38 @@ def run(self): for extension in self.extensions: if extension.name == "toast._libtoast": # We always build the serial extension, so we trigger the build - # on that. - self.build_cmake() + # on that. This function may be called multiple times, so we + # only build if the final output files do not exist. + extpath = self.get_ext_filename(extension.name) + dest_path = Path(self.get_ext_fullpath(extension.name)).resolve() + build_lib = Path(self.build_lib).resolve() + lib_path = os.path.join(build_lib, extpath) + build_temp = Path(self.build_temp).resolve() + source_path = os.path.join(build_temp, "src", extpath) + if not os.path.isfile(source_path): + # The extension needs to be built + print( + f"Compiling extension '{source_path}' with CMake", + flush=True, + ) + self.build_cmake() + else: + print( + f"Compiled extension '{source_path}' already exists", + flush=True, + ) + if not os.path.isfile(dest_path) or not os.path.isfile(lib_path): + # The extension needs to be copied into place + print( + f"Copying built extension to '{dest_path}' and '{lib_path}'", + flush=True, + ) + self.move_output(extension) + else: + print( + f"Copy of extensions already exist at '{dest_path}' and '{lib_path}'", + flush=True, + ) super().run() def build_cmake(self): @@ -131,7 +170,10 @@ def build_cmake(self): if mat is not None: cmake_opts[mat.group(1)] = v - cmake_args = ["-DPYTHON_EXECUTABLE=" + sys.executable] + cmake_args = [ + "-DPython3_ROOT_DIR=" + os.path.dirname(os.path.dirname(sys.executable)) + ] + cmake_args += ["-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"] cfg = "Debug" if self.debug else "Release" build_args = ["--config", cfg] @@ -140,30 +182,42 @@ def build_cmake(self): # Set compilers - if cc is not None: - # Use serial compilers that were used when building MPI - cmake_args += ["-DCMAKE_C_COMPILER={}".format(cc)] - elif "CMAKE_C_COMPILER" in cmake_opts: + if "CMAKE_C_COMPILER" in cmake_opts: # Get these from the environment - cmake_args += [ - "-DCMAKE_C_COMPILER={}".format(cmake_opts["CMAKE_C_COMPILER"]) - ] + cc = cmake_opts["CMAKE_C_COMPILER"] + print( + f"C Compiler: using serial compiler '{cc}' from TOAST_BUILD environment variables" + ) + cmake_args += [f"-DCMAKE_C_COMPILER={cc}"] _ = cmake_opts.pop("CMAKE_C_COMPILER") + elif cc is not None: + # Use serial compilers that were used when building MPI + print( + f"C Compiler: using serial compiler '{cc}' from installed mpi4py package" + ) + cmake_args += ["-DCMAKE_C_COMPILER={}".format(cc)] else: # We just let cmake guess the compilers and hope for the best... + print(f"C Compiler: not specified, will use CMake to discover") pass - if cxx is not None: - # Use serial compilers that were used when building MPI - cmake_args += ["-DCMAKE_CXX_COMPILER={}".format(cxx)] - elif "CMAKE_CXX_COMPILER" in cmake_opts: + if "CMAKE_CXX_COMPILER" in cmake_opts: # Get these from the environment - cmake_args += [ - "-DCMAKE_CXX_COMPILER={}".format(cmake_opts["CMAKE_CXX_COMPILER"]) - ] + cxx = cmake_opts["CMAKE_CXX_COMPILER"] + print( + f"C++ Compiler: using serial compiler '{cxx}' from TOAST_BUILD environment variables" + ) + cmake_args += [f"-DCMAKE_CXX_COMPILER={cxx}"] _ = cmake_opts.pop("CMAKE_CXX_COMPILER") + elif cxx is not None: + # Use serial compilers that were used when building MPI + print( + f"C++ Compiler: using serial compiler '{cxx}' from installed mpi4py package" + ) + cmake_args += ["-DCMAKE_CXX_COMPILER={}".format(cxx)] else: # We just let cmake guess the compilers and hope for the best... + print(f"C++ Compiler: not specified, will use CMake to discover") pass # Append any other TOAST_BUILD_ options to the cmake args @@ -171,7 +225,11 @@ def build_cmake(self): cmake_args += ["-D{}={}".format(k, v)] # Assuming Makefiles - build_args += ["--", "-j2"] + if "CPU_COUNT" in os.environ: + makej = int(os.environ["CPU_COUNT"]) + else: + makej = 2 + build_args += ["--", f"-j{makej}"] self.build_args = build_args @@ -184,31 +242,37 @@ def build_cmake(self): # CMakeLists.txt is in the same directory as this setup.py file cmake_list_dir = os.path.abspath(os.path.dirname(__file__)) print("-" * 10, "Running CMake prepare", "-" * 40) - subprocess.check_call( - ["cmake", cmake_list_dir] + cmake_args, cwd=self.build_temp, env=env - ) + cmake_com = ["cmake", cmake_list_dir] + cmake_args + print("\n".join([f" {x}" for x in cmake_com]), flush=True) + subprocess.check_call(cmake_com, cwd=self.build_temp, env=env) - print("-" * 10, "Building extensions", "-" * 40) + print("-" * 10, "Building extensions", "-" * 40, flush=True) cmake_cmd = ["cmake", "--build", "."] + self.build_args subprocess.check_call(cmake_cmd, cwd=self.build_temp) - # Move from build temp to final position - for ext in self.extensions: - self.move_output(ext) + # If we are running on readthedocs, prepare sphinx inputs + if "READTHEDOCS" in os.environ: + subprocess.check_call([os.path.join("docs", "setup_docs.sh")]) def move_output(self, ext): extpath = self.get_ext_filename(ext.name) build_temp = Path(self.build_temp).resolve() + build_lib = Path(self.build_lib).resolve() dest_path = Path(self.get_ext_fullpath(ext.name)).resolve() source_path = os.path.join(build_temp, "src", extpath) + lib_path = os.path.join(build_lib, extpath) dest_directory = dest_path.parents[0] dest_directory.mkdir(parents=True, exist_ok=True) self.copy_file(source_path, dest_path) + # Also copy from the temp to the lib directory so that + # the --inplace option works + os.makedirs(os.path.dirname(lib_path), exist_ok=True) + self.copy_file(source_path, lib_path) ext_modules = [CMakeExtension("toast._libtoast")] -scripts = glob.glob("pipelines/*.py") +scripts = glob.glob("workflows/*.py") def readme(): @@ -217,7 +281,7 @@ def readme(): conf = dict() -conf["name"] = "toast-cmb" +conf["name"] = "toast" conf["description"] = "Time Ordered Astrophysics Scalable Tools" conf["long_description"] = readme() conf["long_description_content_type"] = "text/markdown" @@ -226,21 +290,70 @@ def readme(): conf["license"] = "BSD" conf["url"] = "https://github.com/hpc4cmb/toast" conf["version"] = get_version() -conf["python_requires"] = ">=3.6.0" +conf["python_requires"] = ">=3.9.0" +conf["setup_requires"] = (["wheel"],) conf["install_requires"] = [ - "cmake", + "tomlkit", + "traitlets>=5.0", "numpy", "scipy", - "healpy", "matplotlib", - "ephem", + "psutil", "h5py", + "pshmem>=1.3.0", + "ruamel.yaml", + "astropy", + "healpy", + "ephem", + "wurlitzer", ] -conf["extras_require"] = {"mpi": ["mpi4py>=3.0"]} -conf["packages"] = find_packages("src") +conf["extras_require"] = { + "mpi": ["mpi4py>=3.0"], + "totalconvolve": ["ducc0"], + "interactive": [ + "ipywidgets", + "plotly", + "plotly-resampler", + ], +} +conf["packages"] = find_packages( + "src", +) conf["package_dir"] = {"": "src"} +conf["include_package_data"] = True +conf["exclude_package_data"] = { + "": ["*.h", "*.c", "*.cpp", "*.hpp"], +} conf["ext_modules"] = ext_modules conf["scripts"] = scripts +conf["entry_points"] = { + "console_scripts": [ + "toast_env = toast.scripts.toast_env:main", + "toast_run = toast.scripts.toast_run:main", + "toast_fake_focalplane = toast.scripts.toast_fake_focalplane:main", + "toast_fake_telescope = toast.scripts.toast_fake_telescope:main", + "toast_ground_schedule = toast.scripts.toast_ground_schedule:main", + "toast_project_schedule = toast.scripts.toast_project_schedule:main", + "toast_analyze_schedule = toast.scripts.toast_analyze_schedule:main", + "toast_satellite_schedule = toast.scripts.toast_satellite_schedule:main", + "toast_benchmark_satellite = toast.scripts.toast_benchmark_satellite:main", + "toast_benchmark_ground_setup = toast.scripts.toast_benchmark_ground_setup:main", + "toast_benchmark_ground = toast.scripts.toast_benchmark_ground:main", + "toast_mini = toast.scripts.toast_mini:main", + "toast_healpix_convert = toast.scripts.toast_healpix_convert:main", + "toast_healpix_coadd = toast.scripts.toast_healpix_coadd:main", + "toast_hdf5_to_spt3g = toast.scripts.toast_hdf5_to_spt3g:main", + "toast_timing_plot = toast.scripts.toast_timing_plot:main", + "toast_obsmatrix_combine = toast.scripts.toast_obsmatrix_combine:main", + "toast_obsmatrix_coadd = toast.scripts.toast_obsmatrix_coadd:main", + "toast_config_verify = toast.scripts.toast_config_verify:main", + "toast_config_compare = toast.scripts.toast_config_compare:main", + "toast_plot_wcs = toast.scripts.toast_plot_wcs:main", + "toast_plot_healpix = toast.scripts.toast_plot_healpix:main", + "toast_overlap_schedule = toast.scripts.toast_overlap_schedule:main", + "toast_map_stats = toast.scripts.toast_map_stats:main", + ] +} conf["cmdclass"] = {"build_ext": CMakeBuild} conf["zip_safe"] = False conf["classifiers"] = [ @@ -249,9 +362,10 @@ def readme(): "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Operating System :: POSIX", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Scientific/Engineering :: Astronomy", ] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 518501954..6960c5b7a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,9 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# TODO temporary +#set(CMAKE_BUILD_TYPE Debug) + add_subdirectory(libtoast) add_subdirectory(toast) diff --git a/src/format_source.sh b/src/format_source.sh index 73f0ceeaf..c62aa78aa 100755 --- a/src/format_source.sh +++ b/src/format_source.sh @@ -17,12 +17,43 @@ if [ "x${unexe}" = "x" ]; then exit 1 fi +umajor=$(uncrustify --version | sed -Ee 's#.*-([0-9]+)\.([0-9]+)\.([0-9]+).*#\1#') +uminor=$(uncrustify --version | sed -Ee 's#.*-([0-9]+)\.([0-9]+)\.([0-9]+).*#\2#') +upatch=$(uncrustify --version | sed -Ee 's#.*-([0-9]+)\.([0-9]+)\.([0-9]+).*#\3#') + +echo "Found uncrustify version ${umajor}.${uminor}.${upatch}" +if [ ${umajor} -eq "0" ]; then + if [ ${uminor} -lt "73" ]; then + echo "This script requires at least uncrustify version 0.73.0" + exit 1 + fi +fi + blkexe=$(which black) if [ "x${blkexe}" = "x" ]; then echo "Cannot find the \"black\" executable. Is it in your PATH?" exit 1 fi +bmajor=$(black --version | awk '{print $3}' | sed -e "s#\([0-9]\+\)\.[0-9]\+.*#\1#") +bminor=$(black --version | awk '{print $3}' | sed -e "s#[0-9]\+\.\([0-9]\+\).*#\1#") + +echo "Found black version ${bmajor}.${bminor}" +if [ ${bmajor} -le "21" ]; then + if [ ${bminor} -lt "5" ]; then + echo "This script requires at least black version 21.5" + exit 1 + fi +fi + +isortexe=$(which isort) +have_isort="yes" +if [ "x${isortexe}" = "x" ]; then + echo "Cannot find the \"isort\" executable. Is it in your PATH?" + echo "Skipping for now." + have_isort="no" +fi + # The uncrustify config file uncfg="${base}/uncrustify.cfg" @@ -38,16 +69,29 @@ blkrun="-l 88" # Black test options blktest="--check" -# Directories to process -cppdirs="libtoast libtoast_mpi toast" -pydirs="toast ../pipelines" +# Note that the "+" argument to "find ... -exec" below passes all found files to the +# exec command in one go. This works because both uncrustify and black accept multiple +# files as arguments. + +# Process directories with C++ files. +find "${base}/libtoast" "${base}/toast" \( -name "*.hpp" -or -name "*.cpp" \) \ + -and -not \( -path '*Random123*' -or -path '*pybind11/*' -or -path '*gtest/*' \) \ + -exec ${unexe} ${unrun} '{}' + & -# Test -for cppd in ${cppdirs}; do - find "${base}/${cppd}" -name "*.hpp" -not -path '*Random123*' -not -path '*pybind11/*' -not -path '*gtest/*' -exec ${unexe} ${unrun} '{}' \; - find "${base}/${cppd}" -name "*.cpp" -not -path '*Random123*' -not -path '*pybind11/*' -not -path '*gtest/*' -exec ${unexe} ${unrun} '{}' \; -done +# Process directories with python files +find "${base}/toast" "${base}/../workflows" -name "*.py" -and -not \ + -path '*pybind11/*' -exec ${blkexe} ${blkrun} '{}' + & +if [ ${have_isort} = "yes" ]; then + find "${base}/toast" "${base}/../workflows" -name "*.py" -and -not \ + -path '*pybind11/*' -exec ${isortexe} --profile black '{}' + & +fi + +# Special case: process files in the scripts directory which do not +# have the .py extension +find "${base}/toast/scripts" -name "toast_*" -exec ${blkexe} ${blkrun} '{}' + & +if [ ${have_isort} = "yes" ]; then + find "${base}/toast/scripts" -name "toast_*" -exec ${isortexe} --profile black '{}' + & +fi -for pyd in ${pydirs}; do - find "${base}/${pyd}" -name "*.py" -not -path '*pybind11/*' -exec ${blkexe} ${blkrun} '{}' \; -done +# Wait for the commands to finish +wait diff --git a/src/libtoast/CMakeLists.txt b/src/libtoast/CMakeLists.txt index f708bb3fa..b12afa4be 100644 --- a/src/libtoast/CMakeLists.txt +++ b/src/libtoast/CMakeLists.txt @@ -20,23 +20,26 @@ add_custom_command(OUTPUT ${versioncpp} set(toast_SOURCES toast.cpp + src/toast_gpu_helpers.cpp src/toast_sys_environment.cpp src/toast_sys_utils.cpp - src/toast_math_lapack.cpp + src/toast_math_linearalgebra.cpp src/toast_math_sf.cpp src/toast_math_rng.cpp src/toast_math_qarray.cpp + src/toast_math_fft_fftw.cpp + src/toast_math_fft_mkl.cpp + src/toast_math_fft_cufft.cpp src/toast_math_fft.cpp - src/toast_math_healpix.cpp src/toast_map_cov.cpp src/toast_fod_psd.cpp src/toast_tod_filter.cpp - src/toast_tod_pointing.cpp src/toast_tod_simnoise.cpp src/toast_atm_utils.cpp src/toast_atm.cpp src/toast_atm_sim.cpp src/toast_atm_observe.cpp + src/toast_template_offset.cpp tests/toast_test_runner.cpp tests/toast_test_env.cpp tests/toast_test_utils.cpp @@ -44,7 +47,6 @@ set(toast_SOURCES tests/toast_test_rng.cpp tests/toast_test_qarray.cpp tests/toast_test_fft.cpp - tests/toast_test_healpix.cpp tests/toast_test_cov.cpp tests/toast_test_polyfilter.cpp ) @@ -62,27 +64,10 @@ target_include_directories(toast BEFORE PUBLIC $ ) -# This compiler definition makes it possible to query the serial library -# to see if we also have the MPI library. - -if(MPI_FOUND) - target_compile_definitions(toast PRIVATE HAVE_MPI=1) -endif(MPI_FOUND) - -if(MPI4PY_FOUND) - target_compile_definitions(toast PRIVATE HAVE_MPI4PY=1) -endif(MPI4PY_FOUND) - # Dependencies target_link_libraries(toast gtest) -if(OpenMP_CXX_FOUND) - target_compile_options(toast PRIVATE "${OpenMP_CXX_FLAGS}") - set_target_properties(toast PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}") - target_link_libraries(toast "${OpenMP_CXX_LIBRARIES}") -endif(OpenMP_CXX_FOUND) - if(AATM_FOUND) target_compile_definitions(toast PRIVATE HAVE_AATM=1) target_include_directories(toast PUBLIC "${AATM_INCLUDE_DIRS}") @@ -123,10 +108,18 @@ endif(MKL_FOUND) if(FFTW_FOUND) target_compile_definitions(toast PRIVATE HAVE_FFTW=1) target_include_directories(toast PUBLIC "${FFTW_INCLUDE_DIRS}") - target_link_libraries(toast "${FFTW_LIBRARIES}") - if(FFTW_DOUBLE_THREADS_LIB_FOUND) + if(FFTW_DOUBLE_OPENMP_LIB_FOUND) target_compile_definitions(toast PRIVATE HAVE_FFTW_THREADS=1) - endif(FFTW_DOUBLE_THREADS_LIB_FOUND) + target_link_libraries(toast "${FFTW_DOUBLE_OPENMP_LIB}") + else() + if(FFTW_DOUBLE_THREADS_LIB_FOUND) + message(WARNING "OpenMP version of FFTW not found. Using pthreads") + message(WARNING "version which may break thread affinity in slurm jobs.") + target_compile_definitions(toast PRIVATE HAVE_FFTW_THREADS=1) + target_link_libraries(toast "${FFTW_DOUBLE_THREADS_LIB}") + endif() + endif() + target_link_libraries(toast "${FFTW_DOUBLE_LIB}") endif(FFTW_FOUND) # LAPACK / BLAS @@ -134,13 +127,29 @@ endif(FFTW_FOUND) if(LAPACK_FOUND) target_compile_definitions(toast PRIVATE HAVE_LAPACK=1) target_compile_definitions(toast PRIVATE "LAPACK_NAMES_${LAPACK_NAMES}") - set_target_properties(toast PROPERTIES LINK_FLAGS - "${LAPACK_LINKER_FLAGS} ${BLAS_LINKER_FLAGS}" - ) target_link_libraries(toast "${LAPACK_LIBRARIES}") target_link_libraries(toast "${BLAS_LIBRARIES}") endif(LAPACK_FOUND) +if(OpenMP_CXX_FOUND) + target_compile_options(toast PRIVATE "${OpenMP_CXX_FLAGS}") + target_link_libraries(toast "${OpenMP_CXX_LIBRARIES}") +endif(OpenMP_CXX_FOUND) + +# CUDA + +# https://cmake.org/cmake/help/latest/module/FindCUDAToolkit.html#module:FindCUDAToolkit +if(CUDAToolkit_FOUND AND NOT CUDA_DISABLED) + message(STATUS "CUDA libs found.") + target_compile_definitions(toast PRIVATE HAVE_CUDALIBS=1) + target_include_directories(toast PRIVATE "${CUDAToolkit_INCLUDE_DIRS}") + target_include_directories(toast PRIVATE "${CUDAToolkit_MATH_INCLUDE_DIRS}") + # there are also static versions of those libs + target_link_libraries(toast CUDA::cudart CUDA::cublas CUDA::cusolver CUDA::cufft CUDA::cufftw) +else() + message(STATUS "CUDA libs not found.") +endif() + # Installation #install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) @@ -152,23 +161,26 @@ endif(LAPACK_FOUND) # Add the serial unit test executable -add_executable(toast_test - toast_test.cpp -) +# add_executable(toast_test +# toast_test.cpp +# ) -if(OpenMP_CXX_FOUND) - target_compile_options(toast_test PRIVATE "${OpenMP_CXX_FLAGS}") - set_target_properties(toast_test PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}") -endif(OpenMP_CXX_FOUND) +# if(OpenMP_CXX_FOUND) +# target_compile_options(toast_test PRIVATE "${OpenMP_CXX_FLAGS}") +# endif(OpenMP_CXX_FOUND) -target_include_directories(toast_test BEFORE PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_SOURCE_DIR}/tests" -) +# target_include_directories(toast_test BEFORE PRIVATE +# "${CMAKE_CURRENT_SOURCE_DIR}" +# "${CMAKE_CURRENT_SOURCE_DIR}/include" +# "${CMAKE_CURRENT_SOURCE_DIR}/tests" +# ) + +# target_link_libraries(toast_test toast) -target_link_libraries(toast_test toast) +# target_link_options(toast_test PRIVATE +# ${LAPACK_LINKER_FLAGS} ${BLAS_LINKER_FLAGS} ${OpenMP_CXX_FLAGS} +# ) -install(TARGETS toast_test DESTINATION ${CMAKE_INSTALL_BINDIR}) +# install(TARGETS toast_test DESTINATION ${CMAKE_INSTALL_BINDIR}) -add_test(NAME serial_tests COMMAND toast_test) +# add_test(NAME serial_tests COMMAND toast_test) diff --git a/src/libtoast/gtest/CMakeLists.txt b/src/libtoast/gtest/CMakeLists.txt index 89276aaef..29b314cab 100644 --- a/src/libtoast/gtest/CMakeLists.txt +++ b/src/libtoast/gtest/CMakeLists.txt @@ -1,24 +1,34 @@ -cmake_minimum_required(VERSION 2.6.2) +# Note: CMake support is community-based. The maintainers do not use CMake +# internally. + +cmake_minimum_required(VERSION 3.20) if (POLICY CMP0048) cmake_policy(SET CMP0048 NEW) endif (POLICY CMP0048) -if (POLICY CMP0063) - cmake_policy(SET CMP0063 NEW) -endif (POLICY CMP0063) +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif (POLICY CMP0077) + +project(googletest-distribution) +set(GOOGLETEST_VERSION 1.12.1) -project( googletest-distribution ) +if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() enable_testing() -option(BUILD_GTEST "Builds the googletest subproject" OFF) +include(CMakeDependentOption) +include(GNUInstallDirs) #Note that googlemock target already builds googletest -option(BUILD_GMOCK "Builds the googlemock subproject" ON) +option(BUILD_GMOCK "Builds the googlemock subproject" OFF) +option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF) if(BUILD_GMOCK) add_subdirectory( googlemock ) -elseif(BUILD_GTEST) +else() add_subdirectory( googletest ) endif() diff --git a/src/libtoast/gtest/CONTRIBUTORS b/src/libtoast/gtest/CONTRIBUTORS new file mode 100644 index 000000000..77397a5b5 --- /dev/null +++ b/src/libtoast/gtest/CONTRIBUTORS @@ -0,0 +1,65 @@ +# 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 +Benoit Sigoure +Bharat Mediratta +Bogdan Piloca +Chandler Carruth +Chris Prince +Chris Taylor +Dan Egnor +Dave MacLachlan +David Anderson +Dean Sturtevant +Eric Roman +Gene Volovich +Hady Zalek +Hal Burch +Jeffrey Yasskin +Jim Keller +Joe Walnes +Jon Wray +Jói Sigurðsson +Keir Mierle +Keith Ray +Kenton Varda +Kostya Serebryany +Krystian Kuzniarek +Lev Makhlis +Manuel Klimek +Mario Tanev +Mark Paskin +Markus Heule +Martijn Vels +Matthew Simmons +Mika Raento +Mike Bland +Miklós Fazekas +Neal Norwitz +Nermin Ozkiranartli +Owen Carlsen +Paneendra Ba +Pasi Valminen +Patrick Hanna +Patrick Riley +Paul Menage +Peter Kaminski +Piotr Kaminski +Preston Jackson +Rainer Klaffenboeck +Russ Cox +Russ Rufer +Sean Mcafee +Sigurður Ásgeirsson +Sverre Sundsdal +Szymon Sobik +Takeshi Yoshino +Tracy Bialik +Vadim Berman +Vlad Losev +Wolfgang Klier +Zhanyong Wan diff --git a/src/libtoast/gtest/googlemock/LICENSE b/src/libtoast/gtest/LICENSE similarity index 100% rename from src/libtoast/gtest/googlemock/LICENSE rename to src/libtoast/gtest/LICENSE diff --git a/src/libtoast/gtest/README.md b/src/libtoast/gtest/README.md index 076484e4f..30edaecf3 100644 --- a/src/libtoast/gtest/README.md +++ b/src/libtoast/gtest/README.md @@ -1,142 +1,141 @@ +# GoogleTest -# Google Test # +### Announcements -[![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest) -[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/BillyDonahue/googletest/branch/master) +#### Live at Head -Welcome to **Google Test**, Google's C++ test framework! +GoogleTest now follows the +[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support). +We recommend +[updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it). -This repository is a merger of the formerly separate GoogleTest and -GoogleMock projects. These were so closely related that it makes sense to -maintain and release them together. +#### Documentation Updates -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! +Our documentation is now live on GitHub Pages at +https://google.github.io/googletest/. We recommend browsing the documentation on +GitHub Pages rather than directly in the repository. -Getting started information for **Google Test** is available in the -[Google Test Primer](googletest/docs/Primer.md) documentation. +#### Release 1.11.0 -**Google Mock** is an extension to Google Test for writing and using C++ mock -classes. See the separate [Google Mock documentation](googlemock/README.md). +[Release 1.11.0](https://github.com/google/googletest/releases/tag/release-1.11.0) +is now available. -More detailed documentation for googletest (including build instructions) are -in its interior [googletest/README.md](googletest/README.md) file. +#### Coming Soon -## Features ## +* We are planning to take a dependency on + [Abseil](https://github.com/abseil/abseil-cpp). +* More documentation improvements are planned. - * An [XUnit](https://en.wikipedia.org/wiki/XUnit) test framework. - * Test discovery. - * A rich set of assertions. - * User-defined assertions. - * Death tests. - * Fatal and non-fatal failures. - * Value-parameterized tests. - * Type-parameterized tests. - * Various options for running the tests. - * XML test report generation. +## Welcome to **GoogleTest**, Google's C++ test framework! -## Platforms ## +This repository is a merger of the formerly separate GoogleTest and GoogleMock +projects. These were so closely related that it makes sense to maintain and +release them together. -Google test has been used on a variety of platforms: +### Getting Started - * Linux - * Mac OS X - * Windows - * Cygwin - * MinGW - * Windows Mobile - * Symbian +See the [GoogleTest User's Guide](https://google.github.io/googletest/) for +documentation. We recommend starting with the +[GoogleTest Primer](https://google.github.io/googletest/primer.html). -## Who Is Using Google Test? ## +More information about building GoogleTest can be found at +[googletest/README.md](googletest/README.md). -In addition to many internal projects at Google, Google Test is also used by -the following notable projects: +## Features - * The [Chromium projects](http://www.chromium.org/) (behind the Chrome - browser and Chrome OS). - * The [LLVM](http://llvm.org/) compiler. - * [Protocol Buffers](https://github.com/google/protobuf), Google's data - interchange format. - * The [OpenCV](http://opencv.org/) computer vision library. +* An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework. +* Test discovery. +* A rich set of assertions. +* User-defined assertions. +* Death tests. +* Fatal and non-fatal failures. +* Value-parameterized tests. +* Type-parameterized tests. +* Various options for running the tests. +* XML test report generation. -## Related Open Source Projects ## +## Supported Platforms -[Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that runs -your test binary, allows you to track its progress via a progress bar, and -displays a list of test failures. Clicking on one shows failure text. Google -Test UI is written in C#. +GoogleTest requires a codebase and compiler compliant with the C++11 standard or +newer. -[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event -listener for Google Test that implements the -[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test -result output. If your test runner understands TAP, you may find it useful. +The GoogleTest code is officially supported on the following platforms. +Operating systems or tools not listed below are community-supported. For +community-supported platforms, patches that do not complicate the code may be +considered. + +If you notice any problems on your platform, please file an issue on the +[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues). +Pull requests containing fixes are welcome! -## Requirements ## +### Operating Systems -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 -. Patches for fixing them are -even more welcome! +* Linux +* macOS +* Windows -### Linux Requirements ### +### Compilers -These are the base requirements to build and use Google Test from a source -package (as described below): +* gcc 5.0+ +* clang 5.0+ +* MSVC 2015+ - * GNU-compatible Make or gmake - * POSIX-standard shell - * POSIX(-2) Regular Expressions (regex.h) - * A C++98-standard-compliant compiler +**macOS users:** Xcode 9.3+ provides clang 5.0+. -### Windows Requirements ### +### Build Systems - * Microsoft Visual C++ v7.1 or newer +* [Bazel](https://bazel.build/) +* [CMake](https://cmake.org/) -### Cygwin Requirements ### +**Note:** Bazel is the build system used by the team internally and in tests. +CMake is supported on a best-effort basis and by the community. - * Cygwin v1.5.25-14 or newer +## Who Is Using GoogleTest? -### Mac OS X Requirements ### +In addition to many internal projects at Google, GoogleTest is also used by the +following notable projects: - * Mac OS X v10.4 Tiger or newer - * Xcode Developer Tools +* The [Chromium projects](http://www.chromium.org/) (behind the Chrome browser + and Chrome OS). +* The [LLVM](http://llvm.org/) compiler. +* [Protocol Buffers](https://github.com/google/protobuf), Google's data + interchange format. +* The [OpenCV](http://opencv.org/) computer vision library. -### Requirements for Contributors ### +## Related Open Source Projects -We welcome patches. If you plan to contribute a patch, you need to -build Google Test and its own tests from a git checkout (described -below), which has further requirements: +[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based +automated test-runner and Graphical User Interface with powerful features for +Windows and Linux platforms. + +[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that +runs your test binary, allows you to track its progress via a progress bar, and +displays a list of test failures. Clicking on one shows failure text. GoogleTest +UI is written in C#. + +[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event +listener for GoogleTest that implements the +[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test +result output. If your test runner understands TAP, you may find it useful. - * [Python](https://www.python.org/) v2.3 or newer (for running some of - the tests and re-generating certain source files from templates) - * [CMake](https://cmake.org/) v2.6.4 or newer +[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that +runs tests from your binary in parallel to provide significant speed-up. -## Regenerating Source Files ## +[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter) +is a VS Code extension allowing to view GoogleTest in a tree view and run/debug +your tests. -Some of Google Test's source files are generated from templates (not -in the C++ sense) using a script. -For example, the -file include/gtest/internal/gtest-type-util.h.pump is used to generate -gtest-type-util.h in the same directory. +[C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS +Code extension allowing to view GoogleTest in a tree view and run/debug your +tests. -You don't need to worry about regenerating the source files -unless you need to modify them. You would then modify the -corresponding `.pump` files and run the '[pump.py](googletest/scripts/pump.py)' -generator script. See the [Pump Manual](googletest/docs/PumpManual.md). +[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser +that generates stub code for GoogleTest. -### Contributing Code ### +## Contributing Changes -We welcome patches. Please read the -[Developer's Guide](googletest/docs/DevGuide.md) -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. +Please read +[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/master/CONTRIBUTING.md) +for details on how to contribute to this project. Happy testing! diff --git a/src/libtoast/gtest/googlemock/CHANGES b/src/libtoast/gtest/googlemock/CHANGES deleted file mode 100644 index d6f2f760e..000000000 --- a/src/libtoast/gtest/googlemock/CHANGES +++ /dev/null @@ -1,126 +0,0 @@ -Changes for 1.7.0: - -* All new improvements in Google Test 1.7.0. -* New feature: matchers DoubleNear(), FloatNear(), - NanSensitiveDoubleNear(), NanSensitiveFloatNear(), - UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(), - WhenSortedBy(), IsEmpty(), and SizeIs(). -* Improvement: Google Mock can now be built as a DLL. -* Improvement: when compiled by a C++11 compiler, matchers AllOf() - and AnyOf() can accept an arbitrary number of matchers. -* Improvement: when compiled by a C++11 compiler, matchers - ElementsAreArray() can accept an initializer list. -* Improvement: when exceptions are enabled, a mock method with no - default action now throws instead crashing the test. -* Improvement: added class testing::StringMatchResultListener to aid - definition of composite matchers. -* Improvement: function return types used in MOCK_METHOD*() macros can - now contain unprotected commas. -* Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT() - are now more strict in ensuring that the value type and the matcher - type are compatible, catching potential bugs in tests. -* Improvement: Pointee() now works on an optional. -* Improvement: the ElementsAreArray() matcher can now take a vector or - iterator range as input, and makes a copy of its input elements - before the conversion to a Matcher. -* Improvement: the Google Mock Generator can now generate mocks for - some class templates. -* Bug fix: mock object destruction triggerred by another mock object's - destruction no longer hangs. -* Improvement: Google Mock Doctor works better with newer Clang and - GCC now. -* Compatibility fixes. -* Bug/warning fixes. - -Changes for 1.6.0: - -* Compilation is much faster and uses much less memory, especially - when the constructor and destructor of a mock class are moved out of - the class body. -* New matchers: Pointwise(), Each(). -* New actions: ReturnPointee() and ReturnRefOfCopy(). -* CMake support. -* Project files for Visual Studio 2010. -* AllOf() and AnyOf() can handle up-to 10 arguments now. -* Google Mock doctor understands Clang error messages now. -* SetArgPointee<> now accepts string literals. -* gmock_gen.py handles storage specifier macros and template return - types now. -* Compatibility fixes. -* Bug fixes and implementation clean-ups. -* Potentially incompatible changes: disables the harmful 'make install' - command in autotools. - -Potentially breaking changes: - -* The description string for MATCHER*() changes from Python-style - interpolation to an ordinary C++ string expression. -* SetArgumentPointee is deprecated in favor of SetArgPointee. -* Some non-essential project files for Visual Studio 2005 are removed. - -Changes for 1.5.0: - - * New feature: Google Mock can be safely used in multi-threaded tests - on platforms having pthreads. - * New feature: function for printing a value of arbitrary type. - * New feature: function ExplainMatchResult() for easy definition of - composite matchers. - * The new matcher API lets user-defined matchers generate custom - explanations more directly and efficiently. - * Better failure messages all around. - * NotNull() and IsNull() now work with smart pointers. - * Field() and Property() now work when the matcher argument is a pointer - passed by reference. - * Regular expression matchers on all platforms. - * Added GCC 4.0 support for Google Mock Doctor. - * Added gmock_all_test.cc for compiling most Google Mock tests - in a single file. - * Significantly cleaned up compiler warnings. - * Bug fixes, better test coverage, and implementation clean-ups. - - Potentially breaking changes: - - * Custom matchers defined using MatcherInterface or MakePolymorphicMatcher() - need to be updated after upgrading to Google Mock 1.5.0; matchers defined - using MATCHER or MATCHER_P* aren't affected. - * Dropped support for 'make install'. - -Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of -Google Test): - - * Works in more environments: Symbian and minGW, Visual C++ 7.1. - * Lighter weight: comes with our own implementation of TR1 tuple (no - more dependency on Boost!). - * New feature: --gmock_catch_leaked_mocks for detecting leaked mocks. - * New feature: ACTION_TEMPLATE for defining templatized actions. - * New feature: the .After() clause for specifying expectation order. - * New feature: the .With() clause for for specifying inter-argument - constraints. - * New feature: actions ReturnArg(), ReturnNew(...), and - DeleteArg(). - * New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(), - and Contains(). - * New feature: utility class MockFunction, useful for checkpoints, etc. - * New feature: functions Value(x, m) and SafeMatcherCast(m). - * New feature: copying a mock object is rejected at compile time. - * New feature: a script for fusing all Google Mock and Google Test - source files for easy deployment. - * Improved the Google Mock doctor to diagnose more diseases. - * Improved the Google Mock generator script. - * Compatibility fixes for Mac OS X and gcc. - * Bug fixes and implementation clean-ups. - -Changes for 1.1.0: - - * New feature: ability to use Google Mock with any testing framework. - * New feature: macros for easily defining new matchers - * New feature: macros for easily defining new actions. - * New feature: more container matchers. - * New feature: actions for accessing function arguments and throwing - exceptions. - * Improved the Google Mock doctor script for diagnosing compiler errors. - * Bug fixes and implementation clean-ups. - -Changes for 1.0.0: - - * Initial Open Source release of Google Mock diff --git a/src/libtoast/gtest/googlemock/CMakeLists.txt b/src/libtoast/gtest/googlemock/CMakeLists.txt index 201dedba5..5c1f0dafe 100644 --- a/src/libtoast/gtest/googlemock/CMakeLists.txt +++ b/src/libtoast/gtest/googlemock/CMakeLists.txt @@ -1,14 +1,13 @@ ######################################################################## +# Note: CMake support is community-based. The maintainers do not use CMake +# internally. +# # CMake build script for Google Mock. # # To run the tests for Google Mock 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) - option(gmock_build_tests "Build all of Google Mock's own tests." OFF) # A directory to find Google Test sources. @@ -37,13 +36,9 @@ endif() # as ${gmock_SOURCE_DIR} and to the root binary directory as # ${gmock_BINARY_DIR}. # Language "C" is required for find_package(Threads). - -if (POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) -endif (POLICY CMP0048) - -project(gmock CXX C) -cmake_minimum_required(VERSION 2.6.2) +cmake_minimum_required(VERSION 3.5) +cmake_policy(SET CMP0048 NEW) +project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() @@ -53,7 +48,17 @@ endif() # targets to the current scope. We are placing Google Test's binary # directory in a subdirectory of our own as VC compilation may break # if they are the same (the default). -add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest") +add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/${gtest_dir}") + + +# These commands only run if this is the main project +if(CMAKE_PROJECT_NAME STREQUAL "gmock" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution") + # 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) +else() + mark_as_advanced(gmock_build_tests) +endif() # Although Google Test's CMakeLists.txt calls this function, the # changes there don't affect the current scope. Therefore we have to @@ -61,22 +66,13 @@ add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest") config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake # Adds Google Mock's and Google Test's header directories to the search path. -include_directories("${gmock_SOURCE_DIR}/include" - "${gmock_SOURCE_DIR}" - "${gtest_SOURCE_DIR}/include" - # This directory is needed to build directly from Google - # Test sources. - "${gtest_SOURCE_DIR}") - -# Summary of tuple support for Microsoft Visual Studio: -# Compiler version(MS) version(cmake) Support -# ---------- ----------- -------------- ----------------------------- -# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple. -# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10 -# VS 2013 12 1800 std::tr1::tuple -if (MSVC AND MSVC_VERSION EQUAL 1700) - add_definitions(/D _VARIADIC_MAX=10) -endif() +set(gmock_build_include_dirs + "${gmock_SOURCE_DIR}/include" + "${gmock_SOURCE_DIR}" + "${gtest_SOURCE_DIR}/include" + # This directory is needed to build directly from Google Test sources. + "${gtest_SOURCE_DIR}") +include_directories(${gmock_build_include_dirs}) ######################################################################## # @@ -86,32 +82,42 @@ endif() # Google Mock libraries. We build them using more strict warnings than what # are used for other targets, to ensure that Google Mock can be compiled by # a user aggressive about warnings. -cxx_library(gmock - "${cxx_strict}" - "${gtest_dir}/src/gtest-all.cc" - src/gmock-all.cc) - -cxx_library(gmock_main - "${cxx_strict}" - "${gtest_dir}/src/gtest-all.cc" - src/gmock-all.cc - src/gmock_main.cc) - +if (MSVC) + cxx_library(gmock + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc) + + cxx_library(gmock_main + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc + src/gmock_main.cc) +else() + cxx_library(gmock "${cxx_strict}" src/gmock-all.cc) + target_link_libraries(gmock PUBLIC gtest) + set_target_properties(gmock PROPERTIES VERSION ${GOOGLETEST_VERSION}) + cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) + target_link_libraries(gmock_main PUBLIC gmock) + set_target_properties(gmock_main PROPERTIES VERSION ${GOOGLETEST_VERSION}) +endif() # If the CMake version supports it, attach header directory information # to the targets for when we are part of a parent build (ie being pulled # in via add_subdirectory() rather than being a standalone build). if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") - target_include_directories(gmock INTERFACE "${gmock_SOURCE_DIR}/include") - target_include_directories(gmock_main INTERFACE "${gmock_SOURCE_DIR}/include") + string(REPLACE ";" "$" dirs "${gmock_build_include_dirs}") + target_include_directories(gmock SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") + target_include_directories(gmock_main SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") endif() ######################################################################## # # Install rules -install(TARGETS gmock gmock_main - DESTINATION lib) -install(DIRECTORY ${gmock_SOURCE_DIR}/include/gmock - DESTINATION include) +install_project(gmock gmock_main) ######################################################################## # @@ -129,18 +135,26 @@ if (gmock_build_tests) # 'make test' or ctest. enable_testing() + if (MINGW OR CYGWIN) + if (CMAKE_VERSION VERSION_LESS "2.8.12") + add_compile_options("-Wa,-mbig-obj") + else() + add_definitions("-Wa,-mbig-obj") + endif() + endif() + ############################################################ # C++ tests built with standard compiler flags. cxx_test(gmock-actions_test gmock_main) cxx_test(gmock-cardinalities_test gmock_main) cxx_test(gmock_ex_test gmock_main) - cxx_test(gmock-generated-actions_test gmock_main) - cxx_test(gmock-generated-function-mockers_test gmock_main) - cxx_test(gmock-generated-internal-utils_test gmock_main) - cxx_test(gmock-generated-matchers_test gmock_main) + cxx_test(gmock-function-mocker_test gmock_main) cxx_test(gmock-internal-utils_test gmock_main) - cxx_test(gmock-matchers_test gmock_main) + cxx_test(gmock-matchers-arithmetic_test gmock_main) + cxx_test(gmock-matchers-comparisons_test gmock_main) + cxx_test(gmock-matchers-containers_test gmock_main) + cxx_test(gmock-matchers-misc_test gmock_main) cxx_test(gmock-more-actions_test gmock_main) cxx_test(gmock-nice-strict_test gmock_main) cxx_test(gmock-port_test gmock_main) @@ -148,7 +162,7 @@ if (gmock_build_tests) cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) cxx_test(gmock_test gmock_main) - if (CMAKE_USE_PTHREADS_INIT) + if (DEFINED GTEST_HAS_PTHREAD) cxx_test(gmock_stress_test gmock) endif() @@ -159,23 +173,20 @@ if (gmock_build_tests) ############################################################ # C++ tests built with non-standard compiler flags. - cxx_library(gmock_main_no_exception "${cxx_no_exception}" - "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - - cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" - "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + if (MSVC) + cxx_library(gmock_main_no_exception "${cxx_no_exception}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010. - # Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that - # conflict with our own definitions. Therefore using our own tuple does not - # work on those compilers. - cxx_library(gmock_main_use_own_tuple "${cxx_use_own_tuple}" + cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - cxx_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" - gmock_main_use_own_tuple test/gmock-spec-builders_test.cc) - endif() + else() + cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc) + target_link_libraries(gmock_main_no_exception PUBLIC gmock) + cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc) + target_link_libraries(gmock_main_no_rtti PUBLIC gmock) + endif() cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" gmock_main_no_exception test/gmock-more-actions_test.cc) diff --git a/src/libtoast/gtest/googlemock/CONTRIBUTORS b/src/libtoast/gtest/googlemock/CONTRIBUTORS deleted file mode 100644 index 6e9ae362b..000000000 --- a/src/libtoast/gtest/googlemock/CONTRIBUTORS +++ /dev/null @@ -1,40 +0,0 @@ -# This file contains a list of people who've made non-trivial -# contribution to the Google C++ Mocking Framework project. People -# who commit code to the project are encouraged to add their names -# here. Please keep the list sorted by first names. - -Benoit Sigoure -Bogdan Piloca -Chandler Carruth -Dave MacLachlan -David Anderson -Dean Sturtevant -Gene Volovich -Hal Burch -Jeffrey Yasskin -Jim Keller -Joe Walnes -Jon Wray -Keir Mierle -Keith Ray -Kostya Serebryany -Lev Makhlis -Manuel Klimek -Mario Tanev -Mark Paskin -Markus Heule -Matthew Simmons -Mike Bland -Neal Norwitz -Nermin Ozkiranartli -Owen Carlsen -Paneendra Ba -Paul Menage -Piotr Kaminski -Russ Rufer -Sverre Sundsdal -Takeshi Yoshino -Vadim Berman -Vlad Losev -Wolfgang Klier -Zhanyong Wan diff --git a/src/libtoast/gtest/googlemock/Makefile.am b/src/libtoast/gtest/googlemock/Makefile.am deleted file mode 100644 index 9adbc5163..000000000 --- a/src/libtoast/gtest/googlemock/Makefile.am +++ /dev/null @@ -1,224 +0,0 @@ -# Automake file - -# Nonstandard package files for distribution. -EXTRA_DIST = LICENSE - -# We may need to build our internally packaged gtest. If so, it will be -# included in the 'subdirs' variable. -SUBDIRS = $(subdirs) - -# This is generated by the configure script, so clean it for distribution. -DISTCLEANFILES = scripts/gmock-config - -# We define the global AM_CPPFLAGS as everything we compile includes from these -# directories. -AM_CPPFLAGS = $(GTEST_CPPFLAGS) -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@ -endif - -# Build rules for libraries. -lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la - -lib_libgmock_la_SOURCES = src/gmock-all.cc - -pkginclude_HEADERS = \ - include/gmock/gmock-actions.h \ - include/gmock/gmock-cardinalities.h \ - include/gmock/gmock-generated-actions.h \ - include/gmock/gmock-generated-function-mockers.h \ - include/gmock/gmock-generated-matchers.h \ - include/gmock/gmock-generated-nice-strict.h \ - include/gmock/gmock-matchers.h \ - include/gmock/gmock-more-actions.h \ - include/gmock/gmock-more-matchers.h \ - include/gmock/gmock-spec-builders.h \ - include/gmock/gmock.h - -pkginclude_internaldir = $(pkgincludedir)/internal -pkginclude_internal_HEADERS = \ - include/gmock/internal/gmock-generated-internal-utils.h \ - include/gmock/internal/gmock-internal-utils.h \ - include/gmock/internal/gmock-port.h \ - include/gmock/internal/custom/gmock-generated-actions.h \ - include/gmock/internal/custom/gmock-matchers.h \ - include/gmock/internal/custom/gmock-port.h - -lib_libgmock_main_la_SOURCES = src/gmock_main.cc -lib_libgmock_main_la_LIBADD = lib/libgmock.la - -# Build rules for 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 - -TESTS= -check_PROGRAMS= -AM_LDFLAGS = $(GTEST_LDFLAGS) - -# This exercises all major components of Google Mock. It also -# verifies that libgmock works. -TESTS += test/gmock-spec-builders_test -check_PROGRAMS += test/gmock-spec-builders_test -test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc -test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la - -# This tests using Google Mock in multiple translation units. It also -# verifies that libgmock_main and libgmock work. -TESTS += test/gmock_link_test -check_PROGRAMS += test/gmock_link_test -test_gmock_link_test_SOURCES = \ - test/gmock_link2_test.cc \ - test/gmock_link_test.cc \ - test/gmock_link_test.h -test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la - -if HAVE_PYTHON - # Tests that fused gmock files compile and work. - TESTS += test/gmock_fused_test - check_PROGRAMS += test/gmock_fused_test - test_gmock_fused_test_SOURCES = \ - fused-src/gmock-gtest-all.cc \ - fused-src/gmock/gmock.h \ - fused-src/gmock_main.cc \ - fused-src/gtest/gtest.h \ - test/gmock_test.cc - test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src" -endif - -# Google Mock source files that we don't compile directly. -GMOCK_SOURCE_INGLUDES = \ - src/gmock-cardinalities.cc \ - src/gmock-internal-utils.cc \ - src/gmock-matchers.cc \ - src/gmock-spec-builders.cc \ - src/gmock.cc - -EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES) - -# C++ tests that we don't compile using autotools. -EXTRA_DIST += \ - test/gmock-actions_test.cc \ - test/gmock_all_test.cc \ - test/gmock-cardinalities_test.cc \ - test/gmock_ex_test.cc \ - test/gmock-generated-actions_test.cc \ - test/gmock-generated-function-mockers_test.cc \ - test/gmock-generated-internal-utils_test.cc \ - test/gmock-generated-matchers_test.cc \ - test/gmock-internal-utils_test.cc \ - test/gmock-matchers_test.cc \ - test/gmock-more-actions_test.cc \ - test/gmock-nice-strict_test.cc \ - test/gmock-port_test.cc \ - test/gmock_stress_test.cc - -# Python tests, which we don't run using autotools. -EXTRA_DIST += \ - test/gmock_leak_test.py \ - test/gmock_leak_test_.cc \ - test/gmock_output_test.py \ - test/gmock_output_test_.cc \ - test/gmock_output_test_golden.txt \ - test/gmock_test_utils.py - -# Nonstandard package files for distribution. -EXTRA_DIST += \ - CHANGES \ - CONTRIBUTORS \ - make/Makefile - -# Pump scripts for generating Google Mock headers. -# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. -EXTRA_DIST += \ - include/gmock/gmock-generated-actions.h.pump \ - include/gmock/gmock-generated-function-mockers.h.pump \ - include/gmock/gmock-generated-matchers.h.pump \ - include/gmock/gmock-generated-nice-strict.h.pump \ - include/gmock/internal/gmock-generated-internal-utils.h.pump \ - include/gmock/internal/custom/gmock-generated-actions.h.pump - -# Script for fusing Google Mock and Google Test source files. -EXTRA_DIST += scripts/fuse_gmock_files.py - -# The Google Mock Generator tool from the cppclean project. -EXTRA_DIST += \ - scripts/generator/LICENSE \ - scripts/generator/README \ - scripts/generator/README.cppclean \ - scripts/generator/cpp/__init__.py \ - scripts/generator/cpp/ast.py \ - scripts/generator/cpp/gmock_class.py \ - scripts/generator/cpp/keywords.py \ - scripts/generator/cpp/tokenize.py \ - scripts/generator/cpp/utils.py \ - scripts/generator/gmock_gen.py - -# Script for diagnosing compiler errors in programs that use Google -# Mock. -EXTRA_DIST += scripts/gmock_doctor.py - -# CMake scripts. -EXTRA_DIST += \ - CMakeLists.txt - -# Microsoft Visual Studio 2005 projects. -EXTRA_DIST += \ - msvc/2005/gmock.sln \ - msvc/2005/gmock.vcproj \ - msvc/2005/gmock_config.vsprops \ - msvc/2005/gmock_main.vcproj \ - msvc/2005/gmock_test.vcproj - -# Microsoft Visual Studio 2010 projects. -EXTRA_DIST += \ - msvc/2010/gmock.sln \ - msvc/2010/gmock.vcxproj \ - msvc/2010/gmock_config.props \ - msvc/2010/gmock_main.vcxproj \ - msvc/2010/gmock_test.vcxproj - -if HAVE_PYTHON -# gmock_test.cc does not really depend on files generated by the -# fused-gmock-internal rule. However, gmock_test.o does, and it is -# important to include test/gmock_test.cc as part of this rule in order to -# prevent compiling gmock_test.o until all dependent files have been -# generated. -$(test_gmock_fused_test_SOURCES): fused-gmock-internal - -# TODO(vladl@google.com): Find a way to add Google Tests's sources here. -fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ - $(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \ - $(lib_libgmock_main_la_SOURCES) \ - scripts/fuse_gmock_files.py - mkdir -p "$(srcdir)/fused-src" - chmod -R u+w "$(srcdir)/fused-src" - rm -f "$(srcdir)/fused-src/gtest/gtest.h" - rm -f "$(srcdir)/fused-src/gmock/gmock.h" - rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc" - "$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src" - cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src" - -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 -# Mock 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 Mock into your build system." - false - -install-data-local: - echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system." - false diff --git a/src/libtoast/gtest/googlemock/README.md b/src/libtoast/gtest/googlemock/README.md index 332beab38..7da60655d 100644 --- a/src/libtoast/gtest/googlemock/README.md +++ b/src/libtoast/gtest/googlemock/README.md @@ -1,333 +1,40 @@ -## Google Mock ## +# Googletest Mocking (gMock) Framework -The Google C++ mocking framework. +### Overview -### Overview ### - -Google's framework for writing and using C++ mock classes. -It can help you derive better designs of your system and write better tests. +Google's framework for writing and using C++ mock classes. It can help you +derive better designs of your system and write better tests. It is inspired by: - * [jMock](http://www.jmock.org/), - * [EasyMock](http://www.easymock.org/), and - * [Hamcrest](http://code.google.com/p/hamcrest/), - -and designed with C++'s specifics in mind. - -Google mock: - - * lets you create mock classes trivially using simple macros. - * supports a rich set of matchers and actions. - * handles unordered, partially ordered, or completely ordered expectations. - * is extensible by users. - -We hope you find it useful! - -### Features ### - - * Provides a declarative syntax for defining mocks. - * Can easily define partial (hybrid) mocks, which are a cross of real - and mock objects. - * Handles functions of arbitrary types and overloaded functions. - * Comes with a rich set of matchers for validating function arguments. - * Uses an intuitive syntax for controlling the behavior of a mock. - * Does automatic verification of expectations (no record-and-replay needed). - * Allows arbitrary (partial) ordering constraints on - function calls to be expressed,. - * Lets a user extend it by defining new matchers and actions. - * Does not use exceptions. - * Is easy to learn and use. - -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! - -Please note that code under [scripts/generator](scripts/generator/) is -from [cppclean](http://code.google.com/p/cppclean/) and released under -the Apache License, which is different from Google Mock's license. - -## Getting Started ## - -If you are new to the project, we suggest that you read the user -documentation in the following order: - - * Learn the [basics](../googletest/docs/Primer.md) of - Google Test, if you choose to use Google Mock with it (recommended). - * Read [Google Mock for Dummies](docs/ForDummies.md). - * Read the instructions below on how to build Google Mock. - -You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation. - -Once you understand the basics, check out the rest of the docs: - - * [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff - at a glance. - * [CookBook](docs/CookBook.md) - recipes for getting things done, - including advanced techniques. - -If you need help, please check the -[KnownIssues](docs/KnownIssues.md) and -[FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before -posting a question on the -[discussion group](http://groups.google.com/group/googlemock). - - -### Using Google Mock Without Google Test ### - -Google Mock is not a testing framework itself. Instead, it needs a -testing framework for writing tests. Google Mock works seamlessly -with [Google Test](http://code.google.com/p/googletest/), but -you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework). - -### Requirements for End Users ### - -Google Mock is implemented on top of [Google Test]( -http://github.com/google/googletest/), and depends on it. -You must use the bundled version of Google Test when using Google Mock. - -You can also easily configure Google Mock to work with another testing -framework, although it will still need Google Test. Please read -["Using_Google_Mock_with_Any_Testing_Framework"]( - docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework) -for instructions. - -Google Mock depends on advanced C++ features and thus requires a more -modern compiler. The following are needed to use Google Mock: - -#### Linux Requirements #### - - * GNU-compatible Make or "gmake" - * POSIX-standard shell - * POSIX(-2) Regular Expressions (regex.h) - * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer) - -#### Windows Requirements #### - - * Microsoft Visual C++ 8.0 SP1 or newer - -#### Mac OS X Requirements #### - - * Mac OS X 10.4 Tiger or newer - * Developer Tools Installed - -### Requirements for Contributors ### - -We welcome patches. If you plan to contribute a patch, you need to -build Google Mock and its tests, which has further requirements: - - * Automake version 1.9 or newer - * Autoconf version 2.59 or newer - * Libtool / Libtoolize - * Python version 2.3 or newer (for running some of the tests and - re-generating certain source files from templates) - -### Building Google Mock ### - -#### Preparing to Build (Unix only) #### - -If you are using a Unix system and plan to use the GNU Autotools build -system to build Google Mock (described below), you'll need to -configure it now. - -To prepare the Autotools build system: - - cd googlemock - autoreconf -fvi - -To build Google Mock 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. - -This section shows how you can integrate Google Mock into your -existing build system. - -Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test -in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To -build Google Mock, create a library build target (or a project as -called by Visual Studio and Xcode) to compile - - ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc - -with - - ${GTEST_DIR}/include and ${GMOCK_DIR}/include - -in the system header search path, and - - ${GTEST_DIR} and ${GMOCK_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} \ - -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ - -pthread -c ${GTEST_DIR}/src/gtest-all.cc - g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ - -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ - -pthread -c ${GMOCK_DIR}/src/gmock-all.cc - ar -rv libgmock.a gtest-all.o gmock-all.o - -(We need -pthread as Google Test and Google Mock use threads.) - -Next, you should compile your test source file with -${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search -path, and link it with gmock and any other necessary libraries: - - g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \ - -pthread path/to/your_test.cc libgmock.a -o your_test - -As an example, the make/ directory contains a Makefile that you can -use to build Google Mock on systems where GNU make is available -(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google -Mock's own tests. Instead, it just builds the Google Mock 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 ${GMOCK_DIR}/make - make - ./gmock_test - -If you see errors, try to tweak the contents of -[make/Makefile](make/Makefile) to make them go away. - -### Windows ### - -The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010 -directory contains VC++ 2010 projects for building Google Mock and -selected tests. - -Change to the appropriate directory and run "msbuild gmock.sln" to -build the library and tests (or open the gmock.sln in the MSVC IDE). -If you want to create your own project to use with Google Mock, you'll -have to configure it to use the `gmock_config` propety sheet. For that: - - * Open the Property Manager window (View | Other Windows | Property Manager) - * Right-click on your project and select "Add Existing Property Sheet..." - * Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it. - * In Project Properties | Configuration Properties | General | Additional - Include Directories, type /include. - -### Tweaking Google Mock ### - -Google Mock 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 Mock 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 [${GTEST\_DIR}/include/gtest/internal/gtest-port.h]( -../googletest/include/gtest/internal/gtest-port.h). - -### Choosing a TR1 Tuple Library ### - -Google Mock uses the C++ Technical Report 1 (TR1) tuple library -heavily. Unfortunately TR1 tuple is not yet widely available with all -compilers. The good news is that Google Test 1.4.0+ implements a -subset of TR1 tuple that's enough for Google Mock's need. Google Mock -will automatically use that implementation when the compiler doesn't -provide TR1 tuple. - -Usually you don't need to care about which tuple library Google Test -and Google Mock use. However, if your project already uses TR1 tuple, -you need to tell Google Test and Google Mock 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, Google Mock, and -your tests. If you want to force Google Test and Google Mock to use -their own tuple library, just add - - -DGTEST_USE_OWN_TR1_TUPLE=1 - -to the compiler flags instead. - -If you want to use Boost's TR1 tuple library with Google Mock, please -refer to the Boost website (http://www.boost.org/) for how to obtain -it and set it up. - -### As a Shared Library (DLL) ### - -Google Mock is compact, so most users can build and link it as a static -library for the simplicity. Google Mock can be used as a DLL, but the -same DLL must contain Google Test as well. See -[Google Test's README][gtest_readme] -for instructions on how to set up necessary compiler settings. - -### Tweaking Google Mock ### - -Most of Google Test's control macros apply to Google Mock as well. -Please see [Google Test's README][gtest_readme] for how to tweak them. - -### Upgrading from an Earlier Version ### - -We strive to keep Google Mock 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 Mock. - -#### Upgrading from 1.1.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](../googletest/#choosing-a-tr1-tuple-library)". - -#### Upgrading from 1.4.0 or Earlier #### - -On platforms where the pthread library is available, Google Test and -Google Mock use it in order to be thread-safe. For this to work, you -may need to tweak your compiler and/or linker flags. Please see the -"[Multi-threaded Tests](../googletest#multi-threaded-tests -)" section in file Google Test's README for what you may need to do. - -If you have custom matchers defined using `MatcherInterface` or -`MakePolymorphicMatcher()`, you'll need to update their definitions to -use the new matcher API ( -[monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers), -[polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)). -Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected. - -### Developing Google Mock ### - -This section discusses how to make your own changes to Google Mock. - -#### Testing Google Mock 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'll need Autotools. First, make sure you have followed -the instructions above to configure Google Mock. -Then, create a build output directory and enter it. Next, - - ${GMOCK_DIR}/configure # try --help for more info - -Once you have successfully configured Google Mock, the build steps are -standard for GNU-style OSS packages. - - make # Standard makefile following GNU conventions - make check # Builds and runs all tests - all should pass. - -Note that when building your project against Google Mock, you are building -against Google Test as well. There is no need to configure Google Test -separately. - -#### Contributing a Patch #### - -We welcome patches. -Please read the [Developer's Guide](docs/DevGuide.md) -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. - -Happy testing! - -[gtest_readme]: ../googletest/README.md "googletest" +* [jMock](http://www.jmock.org/) +* [EasyMock](http://www.easymock.org/) +* [Hamcrest](http://code.google.com/p/hamcrest/) + +It is designed with C++'s specifics in mind. + +gMock: + +- Provides a declarative syntax for defining mocks. +- Can define partial (hybrid) mocks, which are a cross of real and mock + objects. +- Handles functions of arbitrary types and overloaded functions. +- Comes with a rich set of matchers for validating function arguments. +- Uses an intuitive syntax for controlling the behavior of a mock. +- Does automatic verification of expectations (no record-and-replay needed). +- Allows arbitrary (partial) ordering constraints on function calls to be + expressed. +- Lets a user extend it by defining new matchers and actions. +- Does not use exceptions. +- Is easy to learn and use. + +Details and examples can be found here: + +* [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html) +* [Legacy gMock FAQ](https://google.github.io/googletest/gmock_faq.html) +* [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html) +* [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html) + +GoogleMock is a part of +[GoogleTest C++ testing framework](http://github.com/google/googletest/) and a +subject to the same requirements. diff --git a/src/libtoast/gtest/googlemock/cmake/gmock.pc.in b/src/libtoast/gtest/googlemock/cmake/gmock.pc.in new file mode 100644 index 000000000..23c67b5c8 --- /dev/null +++ b/src/libtoast/gtest/googlemock/cmake/gmock.pc.in @@ -0,0 +1,10 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: gmock +Description: GoogleMock (without main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gtest = @PROJECT_VERSION@ +Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/src/libtoast/gtest/googlemock/cmake/gmock_main.pc.in b/src/libtoast/gtest/googlemock/cmake/gmock_main.pc.in new file mode 100644 index 000000000..66ffea7f4 --- /dev/null +++ b/src/libtoast/gtest/googlemock/cmake/gmock_main.pc.in @@ -0,0 +1,10 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: gmock_main +Description: GoogleMock (with main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gmock = @PROJECT_VERSION@ +Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/src/libtoast/gtest/googlemock/configure.ac b/src/libtoast/gtest/googlemock/configure.ac deleted file mode 100644 index 3b740f205..000000000 --- a/src/libtoast/gtest/googlemock/configure.ac +++ /dev/null @@ -1,146 +0,0 @@ -m4_include(../googletest/m4/acx_pthread.m4) - -AC_INIT([Google C++ Mocking Framework], - [1.7.0], - [googlemock@googlegroups.com], - [gmock]) - -# Provide various options to initialize the Autoconf and configure processes. -AC_PREREQ([2.59]) -AC_CONFIG_SRCDIR([./LICENSE]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_HEADERS([build-aux/config.h]) -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES([scripts/gmock-config], [chmod +x scripts/gmock-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" != ":"]) - -# TODO(chandlerc@google.com) Check for the necessary system headers. - -# 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) - -# GoogleMock currently has hard dependencies upon GoogleTest above and beyond -# running its own test suite, so we both provide our own version in -# a subdirectory and provide some logic to use a custom version or a system -# installed version. -AC_ARG_WITH([gtest], - [AS_HELP_STRING([--with-gtest], - [Specifies how to find the gtest package. If no - arguments are given, the default behavior, a - system installed gtest will be used if present, - and an internal version built otherwise. If a - path is provided, the gtest built or installed at - that prefix will be used.])], - [], - [with_gtest=yes]) -AC_ARG_ENABLE([external-gtest], - [AS_HELP_STRING([--disable-external-gtest], - [Disables any detection or use of a system - installed or user provided gtest. Any option to - '--with-gtest' is ignored. (Default is enabled.)]) - ], [], [enable_external_gtest=yes]) -AS_IF([test "x$with_gtest" == "xno"], - [AC_MSG_ERROR([dnl -Support for GoogleTest was explicitly disabled. Currently GoogleMock has a hard -dependency upon GoogleTest to build, please provide a version, or allow -GoogleMock to use any installed version and fall back upon its internal -version.])]) - -# Setup various GTEST variables. TODO(chandlerc@google.com): When these are -# used below, they should be used such that any pre-existing values always -# trump values we set them to, so that they can be used to selectively override -# details of the detection process. -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_BUILT_GTEST="no" - -GTEST_MIN_VERSION="1.7.0" - -AS_IF([test "x${enable_external_gtest}" = "xyes"], - [# Begin filling in variables as we are able. - AS_IF([test "x${with_gtest}" != "xyes"], - [AS_IF([test -x "${with_gtest}/scripts/gtest-config"], - [GTEST_CONFIG="${with_gtest}/scripts/gtest-config"], - [GTEST_CONFIG="${with_gtest}/bin/gtest-config"]) - AS_IF([test -x "${GTEST_CONFIG}"], [], - [AC_MSG_ERROR([dnl -Unable to locate either a built or installed Google Test at '${with_gtest}'.]) - ])]) - - AS_IF([test -x "${GTEST_CONFIG}"], [], - [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) - AS_IF([test -x "${GTEST_CONFIG}"], - [AC_MSG_CHECKING([for Google Test version >= ${GTEST_MIN_VERSION}]) - AS_IF([${GTEST_CONFIG} --min-version=${GTEST_MIN_VERSION}], - [AC_MSG_RESULT([yes]) - HAVE_BUILT_GTEST="yes"], - [AC_MSG_RESULT([no])])])]) - -AS_IF([test "x${HAVE_BUILT_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_CONFIG_SUBDIRS([../googletest]) - # GTEST_CONFIG needs to be executable both in a Makefile environmont and - # in a shell script environment, so resolve an absolute path for it here. - GTEST_CONFIG="`pwd -P`/../googletest/scripts/gtest-config" - GTEST_CPPFLAGS='-I$(top_srcdir)/../googletest/include' - GTEST_CXXFLAGS='-g' - GTEST_LDFLAGS='' - GTEST_LIBS='$(top_builddir)/../googletest/lib/libgtest.la' - GTEST_VERSION="${GTEST_MIN_VERSION}"]) - -# 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 diff --git a/src/libtoast/gtest/googlemock/docs/CheatSheet.md b/src/libtoast/gtest/googlemock/docs/CheatSheet.md deleted file mode 100644 index ef4451b87..000000000 --- a/src/libtoast/gtest/googlemock/docs/CheatSheet.md +++ /dev/null @@ -1,562 +0,0 @@ - - -# Defining a Mock Class # - -## Mocking a Normal Class ## - -Given -``` -class Foo { - ... - virtual ~Foo(); - virtual int GetSize() const = 0; - virtual string Describe(const char* name) = 0; - virtual string Describe(int type) = 0; - virtual bool Process(Bar elem, int count) = 0; -}; -``` -(note that `~Foo()` **must** be virtual) we can define its mock as -``` -#include "gmock/gmock.h" - -class MockFoo : public Foo { - MOCK_CONST_METHOD0(GetSize, int()); - MOCK_METHOD1(Describe, string(const char* name)); - MOCK_METHOD1(Describe, string(int type)); - MOCK_METHOD2(Process, bool(Bar elem, int count)); -}; -``` - -To create a "nice" mock object which ignores all uninteresting calls, -or a "strict" mock object, which treats them as failures: -``` -NiceMock nice_foo; // The type is a subclass of MockFoo. -StrictMock strict_foo; // The type is a subclass of MockFoo. -``` - -## Mocking a Class Template ## - -To mock -``` -template -class StackInterface { - public: - ... - virtual ~StackInterface(); - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; -``` -(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: -``` -template -class MockStack : public StackInterface { - public: - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Specifying Calling Conventions for Mock Functions ## - -If your mock function doesn't use the default calling convention, you -can specify it by appending `_WITH_CALLTYPE` to any of the macros -described in the previous two sections and supplying the calling -convention as the first argument to the macro. For example, -``` - MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); - MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); -``` -where `STDMETHODCALLTYPE` is defined by `` on Windows. - -# Using Mocks in Tests # - -The typical flow is: - 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. - 1. Create the mock objects. - 1. Optionally, set the default actions of the mock objects. - 1. Set your expectations on the mock objects (How will they be called? What wil they do?). - 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](../../googletest/) assertions. - 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. - -Here is an example: -``` -using ::testing::Return; // #1 - -TEST(BarTest, DoesThis) { - MockFoo foo; // #2 - - ON_CALL(foo, GetSize()) // #3 - .WillByDefault(Return(1)); - // ... other default actions ... - - EXPECT_CALL(foo, Describe(5)) // #4 - .Times(3) - .WillRepeatedly(Return("Category 5")); - // ... other expectations ... - - EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 -} // #6 -``` - -# Setting Default Actions # - -Google Mock has a **built-in default action** for any function that -returns `void`, `bool`, a numeric value, or a pointer. - -To customize the default action for functions with return type `T` globally: -``` -using ::testing::DefaultValue; - -// Sets the default value to be returned. T must be CopyConstructible. -DefaultValue::Set(value); -// Sets a factory. Will be invoked on demand. T must be MoveConstructible. -// T MakeT(); -DefaultValue::SetFactory(&MakeT); -// ... use the mocks ... -// Resets the default value. -DefaultValue::Clear(); -``` - -To customize the default action for a particular method, use `ON_CALL()`: -``` -ON_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .WillByDefault(action); -``` - -# Setting Expectations # - -`EXPECT_CALL()` sets **expectations** on a mock method (How will it be -called? What will it do?): -``` -EXPECT_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .Times(cardinality) ? - .InSequence(sequences) * - .After(expectations) * - .WillOnce(action) * - .WillRepeatedly(action) ? - .RetiresOnSaturation(); ? -``` - -If `Times()` is omitted, the cardinality is assumed to be: - - * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; - * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or - * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. - -A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. - -# Matchers # - -A **matcher** matches a _single_ argument. You can use it inside -`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value -directly: - -| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | -|:------------------------------|:----------------------------------------| -| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | - -Built-in matchers (where `argument` is the function argument) are -divided into several categories: - -## Wildcard ## -|`_`|`argument` can be any value of the correct type.| -|:--|:-----------------------------------------------| -|`A()` or `An()`|`argument` can be any value of type `type`. | - -## Generic Comparison ## - -|`Eq(value)` or `value`|`argument == value`| -|:---------------------|:------------------| -|`Ge(value)` |`argument >= value`| -|`Gt(value)` |`argument > value` | -|`Le(value)` |`argument <= value`| -|`Lt(value)` |`argument < value` | -|`Ne(value)` |`argument != value`| -|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| -|`NotNull()` |`argument` is a non-null pointer (raw or smart).| -|`Ref(variable)` |`argument` is a reference to `variable`.| -|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| - -Except `Ref()`, these matchers make a _copy_ of `value` in case it's -modified or destructed later. If the compiler complains that `value` -doesn't have a public copy constructor, try wrap it in `ByRef()`, -e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure -`non_copyable_value` is not changed afterwards, or the meaning of your -matcher will be changed. - -## Floating-Point Matchers ## - -|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| -|:-------------------|:----------------------------------------------------------------------------------------------| -|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | -|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | -|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | - -The above matchers use ULP-based comparison (the same as used in -[Google Test](../../googletest/)). They -automatically pick a reasonable error bound based on the absolute -value of the expected value. `DoubleEq()` and `FloatEq()` conform to -the IEEE standard, which requires comparing two NaNs for equality to -return false. The `NanSensitive*` version instead treats two NaNs as -equal, which is often what a user wants. - -|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| -|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| -|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | -|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | -|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | - -## String Matchers ## - -The `argument` can be either a C string or a C++ string object: - -|`ContainsRegex(string)`|`argument` matches the given regular expression.| -|:----------------------|:-----------------------------------------------| -|`EndsWith(suffix)` |`argument` ends with string `suffix`. | -|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | -|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| -|`StartsWith(prefix)` |`argument` starts with string `prefix`. | -|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | -|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| -|`StrEq(string)` |`argument` is equal to `string`. | -|`StrNe(string)` |`argument` is not equal to `string`. | - -`ContainsRegex()` and `MatchesRegex()` use the regular expression -syntax defined -[here](../../googletest/docs/AdvancedGuide.md#regular-expression-syntax). -`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide -strings as well. - -## Container Matchers ## - -Most STL-style containers support `==`, so you can use -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. If you want to write the elements in-line, -match them more flexibly, or get more informative messages, you can use: - -| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | -|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| -| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | -| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | -| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | -| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | -| `IsEmpty()` | `argument` is an empty container (`container.empty()`). | -| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | -| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | -| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | -| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | -| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | -| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | - -Notes: - - * These matchers can also match: - 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and - 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). - * The array being matched may be multi-dimensional (i.e. its elements can be arrays). - * `m` in `Pointwise(m, ...)` should be a matcher for `::testing::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: - -``` -using ::testing::get; -MATCHER(FooEq, "") { - return get<0>(arg).Equals(get<1>(arg)); -} -... -EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); -``` - -## Member Matchers ## - -|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| -|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| -|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| -|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | -|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| - -## Matching the Result of a Function or Functor ## - -|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| -|:---------------|:---------------------------------------------------------------------| - -## Pointer Matchers ## - -|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| -|:-----------|:-----------------------------------------------------------------------------------------------| -|`WhenDynamicCastTo(m)`| when `argument` is passed through `dynamic_cast()`, it matches matcher `m`. | - -## Multiargument Matchers ## - -Technically, all matchers match a _single_ value. A "multi-argument" -matcher is just one that matches a _tuple_. The following matchers can -be used to match a tuple `(x, y)`: - -|`Eq()`|`x == y`| -|:-----|:-------| -|`Ge()`|`x >= y`| -|`Gt()`|`x > y` | -|`Le()`|`x <= y`| -|`Lt()`|`x < y` | -|`Ne()`|`x != y`| - -You can use the following selectors to pick a subset of the arguments -(or reorder them) to participate in the matching: - -|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| -|:-----------|:-------------------------------------------------------------------| -|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| - -## Composite Matchers ## - -You can make a matcher from one or more other matchers: - -|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| -|:-----------------------|:---------------------------------------------------| -|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| -|`Not(m)` |`argument` doesn't match matcher `m`. | - -## Adapters for Matchers ## - -|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| -|:------------------|:--------------------------------------| -|`SafeMatcherCast(m)`| [safely casts](CookBook.md#casting-matchers) matcher `m` to type `Matcher`. | -|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| - -## Matchers as Predicates ## - -|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| -|:------------------|:---------------------------------------------------------------------------------------------| -|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | -|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | - -## Defining Matchers ## - -| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | -|:-------------------------------------------------|:------------------------------------------------------| -| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | - -**Notes:** - - 1. The `MATCHER*` macros cannot be used inside a function or class. - 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). - 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. - -## Matchers as Test Assertions ## - -|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](../../googletest/docs/Primer.md#assertions) if the value of `expression` doesn't match matcher `m`.| -|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| -|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | - -# Actions # - -**Actions** specify what a mock function should do when invoked. - -## Returning a Value ## - -|`Return()`|Return from a `void` mock function.| -|:---------|:----------------------------------| -|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| -|`ReturnArg()`|Return the `N`-th (0-based) argument.| -|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| -|`ReturnNull()`|Return a null pointer. | -|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| -|`ReturnRef(variable)`|Return a reference to `variable`. | -|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| - -## Side Effects ## - -|`Assign(&variable, value)`|Assign `value` to variable.| -|:-------------------------|:--------------------------| -| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | -| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | -| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | -|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| -|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| -|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| -|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| -|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| - -## Using a Function or a Functor as an Action ## - -|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| -|:----------|:-----------------------------------------------------------------------------------------------------------------| -|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | -|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | -|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | -|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| - -The return value of the invoked function is used as the return value -of the action. - -When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: -``` - double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } - ... - EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); -``` - -In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, -``` - InvokeArgument<2>(5, string("Hi"), ByRef(foo)) -``` -calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. - -## Default Action ## - -|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| -|:------------|:--------------------------------------------------------------------| - -**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. - -## Composite Actions ## - -|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | -|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| -|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | -|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | -|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | -|`WithoutArgs(a)` |Perform action `a` without any arguments. | - -## Defining Actions ## - -| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | -|:--------------------------------------|:---------------------------------------------------------------------------------------| -| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | -| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | - -The `ACTION*` macros cannot be used inside a function or class. - -# Cardinalities # - -These are used in `Times()` to specify how many times a mock function will be called: - -|`AnyNumber()`|The function can be called any number of times.| -|:------------|:----------------------------------------------| -|`AtLeast(n)` |The call is expected at least `n` times. | -|`AtMost(n)` |The call is expected at most `n` times. | -|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| -|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| - -# Expectation Order # - -By default, the expectations can be matched in _any_ order. If some -or all expectations must be matched in a given order, there are two -ways to specify it. They can be used either independently or -together. - -## The After Clause ## - -``` -using ::testing::Expectation; -... -Expectation init_x = EXPECT_CALL(foo, InitX()); -Expectation init_y = EXPECT_CALL(foo, InitY()); -EXPECT_CALL(foo, Bar()) - .After(init_x, init_y); -``` -says that `Bar()` can be called only after both `InitX()` and -`InitY()` have been called. - -If you don't know how many pre-requisites an expectation has when you -write it, you can use an `ExpectationSet` to collect them: - -``` -using ::testing::ExpectationSet; -... -ExpectationSet all_inits; -for (int i = 0; i < element_count; i++) { - all_inits += EXPECT_CALL(foo, InitElement(i)); -} -EXPECT_CALL(foo, Bar()) - .After(all_inits); -``` -says that `Bar()` can be called only after all elements have been -initialized (but we don't care about which elements get initialized -before the others). - -Modifying an `ExpectationSet` after using it in an `.After()` doesn't -affect the meaning of the `.After()`. - -## Sequences ## - -When you have a long chain of sequential expectations, it's easier to -specify the order using **sequences**, which don't require you to given -each expectation in the chain a different name. All expected
-calls
in the same sequence must occur in the order they are -specified. - -``` -using ::testing::Sequence; -Sequence s1, s2; -... -EXPECT_CALL(foo, Reset()) - .InSequence(s1, s2) - .WillOnce(Return(true)); -EXPECT_CALL(foo, GetSize()) - .InSequence(s1) - .WillOnce(Return(1)); -EXPECT_CALL(foo, Describe(A())) - .InSequence(s2) - .WillOnce(Return("dummy")); -``` -says that `Reset()` must be called before _both_ `GetSize()` _and_ -`Describe()`, and the latter two can occur in any order. - -To put many expectations in a sequence conveniently: -``` -using ::testing::InSequence; -{ - InSequence dummy; - - EXPECT_CALL(...)...; - EXPECT_CALL(...)...; - ... - EXPECT_CALL(...)...; -} -``` -says that all expected calls in the scope of `dummy` must occur in -strict order. The name `dummy` is irrelevant.) - -# Verifying and Resetting a Mock # - -Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: -``` -using ::testing::Mock; -... -// Verifies and removes the expectations on mock_obj; -// returns true iff successful. -Mock::VerifyAndClearExpectations(&mock_obj); -... -// Verifies and removes the expectations on mock_obj; -// also removes the default actions set by ON_CALL(); -// returns true iff successful. -Mock::VerifyAndClear(&mock_obj); -``` - -You can also tell Google Mock that a mock object can be leaked and doesn't -need to be verified: -``` -Mock::AllowLeak(&mock_obj); -``` - -# Mock Classes # - -Google Mock defines a convenient mock class template -``` -class MockFunction { - public: - MOCK_METHODn(Call, R(A1, ..., An)); -}; -``` -See this [recipe](CookBook.md#using-check-points) for one application of it. - -# Flags # - -| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | -|:-------------------------------|:----------------------------------------------| -| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | diff --git a/src/libtoast/gtest/googlemock/docs/CookBook.md b/src/libtoast/gtest/googlemock/docs/CookBook.md deleted file mode 100644 index c52f1009d..000000000 --- a/src/libtoast/gtest/googlemock/docs/CookBook.md +++ /dev/null @@ -1,3675 +0,0 @@ - - -You can find recipes for using Google Mock here. If you haven't yet, -please read the [ForDummies](ForDummies.md) document first to make sure you understand -the basics. - -**Note:** Google Mock lives in the `testing` name space. For -readability, it is recommended to write `using ::testing::Foo;` once in -your file before using the name `Foo` defined by Google Mock. We omit -such `using` statements in this page for brevity, but you should do it -in your own code. - -# Creating Mock Classes # - -## Mocking Private or Protected Methods ## - -You must always put a mock method definition (`MOCK_METHOD*`) in a -`public:` section of the mock class, regardless of the method being -mocked being `public`, `protected`, or `private` in the base class. -This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function -from outside of the mock class. (Yes, C++ allows a subclass to change -the access level of a virtual function in the base class.) Example: - -``` -class Foo { - public: - ... - virtual bool Transform(Gadget* g) = 0; - - protected: - virtual void Resume(); - - private: - virtual int GetTimeOut(); -}; - -class MockFoo : public Foo { - public: - ... - MOCK_METHOD1(Transform, bool(Gadget* g)); - - // The following must be in the public section, even though the - // methods are protected or private in the base class. - MOCK_METHOD0(Resume, void()); - MOCK_METHOD0(GetTimeOut, int()); -}; -``` - -## Mocking Overloaded Methods ## - -You can mock overloaded functions as usual. No special attention is required: - -``` -class Foo { - ... - - // Must be virtual as we'll inherit from Foo. - virtual ~Foo(); - - // Overloaded on the types and/or numbers of arguments. - virtual int Add(Element x); - virtual int Add(int times, Element x); - - // Overloaded on the const-ness of this object. - virtual Bar& GetBar(); - virtual const Bar& GetBar() const; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Add, int(Element x)); - MOCK_METHOD2(Add, int(int times, Element x); - - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -``` - -**Note:** if you don't mock all versions of the overloaded method, the -compiler will give you a warning about some methods in the base class -being hidden. To fix that, use `using` to bring them in scope: - -``` -class MockFoo : public Foo { - ... - using Foo::Add; - MOCK_METHOD1(Add, int(Element x)); - // We don't want to mock int Add(int times, Element x); - ... -}; -``` - -## Mocking Class Templates ## - -To mock a class template, append `_T` to the `MOCK_*` macros: - -``` -template -class StackInterface { - ... - // Must be virtual as we'll inherit from StackInterface. - virtual ~StackInterface(); - - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; - -template -class MockStack : public StackInterface { - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Mocking Nonvirtual Methods ## - -Google Mock can mock non-virtual functions to be used in what we call _hi-perf -dependency injection_. - -In this case, instead of sharing a common base class with the real -class, your mock class will be _unrelated_ to the real class, but -contain methods with the same signatures. The syntax for mocking -non-virtual methods is the _same_ as mocking virtual methods: - -``` -// A simple packet stream class. None of its members is virtual. -class ConcretePacketStream { - public: - void AppendPacket(Packet* new_packet); - const Packet* GetPacket(size_t packet_number) const; - size_t NumberOfPackets() const; - ... -}; - -// A mock packet stream class. It inherits from no other, but defines -// GetPacket() and NumberOfPackets(). -class MockPacketStream { - public: - MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); - MOCK_CONST_METHOD0(NumberOfPackets, size_t()); - ... -}; -``` - -Note that the mock class doesn't define `AppendPacket()`, unlike the -real class. That's fine as long as the test doesn't need to call it. - -Next, you need a way to say that you want to use -`ConcretePacketStream` in production code, and use `MockPacketStream` -in tests. Since the functions are not virtual and the two classes are -unrelated, you must specify your choice at _compile time_ (as opposed -to run time). - -One way to do it is to templatize your code that needs to use a packet -stream. More specifically, you will give your code a template type -argument for the type of the packet stream. In production, you will -instantiate your template with `ConcretePacketStream` as the type -argument. In tests, you will instantiate the same template with -`MockPacketStream`. For example, you may write: - -``` -template -void CreateConnection(PacketStream* stream) { ... } - -template -class PacketReader { - public: - void ReadPackets(PacketStream* stream, size_t packet_num); -}; -``` - -Then you can use `CreateConnection()` and -`PacketReader` in production code, and use -`CreateConnection()` and -`PacketReader` in tests. - -``` - MockPacketStream mock_stream; - EXPECT_CALL(mock_stream, ...)...; - .. set more expectations on mock_stream ... - PacketReader reader(&mock_stream); - ... exercise reader ... -``` - -## Mocking Free Functions ## - -It's possible to use Google Mock to mock a free function (i.e. a -C-style function or a static method). You just need to rewrite your -code to use an interface (abstract class). - -Instead of calling a free function (say, `OpenFile`) directly, -introduce an interface for it and have a concrete subclass that calls -the free function: - -``` -class FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) = 0; -}; - -class File : public FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) { - return OpenFile(path, mode); - } -}; -``` - -Your code should talk to `FileInterface` to open a file. Now it's -easy to mock out the function. - -This may seem much hassle, but in practice you often have multiple -related functions that you can put in the same interface, so the -per-function syntactic overhead will be much lower. - -If you are concerned about the performance overhead incurred by -virtual functions, and profiling confirms your concern, you can -combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). - -## The Nice, the Strict, and the Naggy ## - -If a mock method has no `EXPECT_CALL` spec but is called, Google Mock -will print a warning about the "uninteresting call". The rationale is: - - * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. - * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. - -However, sometimes you may want to suppress all "uninteresting call" -warnings, while sometimes you may want the opposite, i.e. to treat all -of them as errors. Google Mock lets you make the decision on a -per-mock-object basis. - -Suppose your test uses a mock class `MockFoo`: - -``` -TEST(...) { - MockFoo mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -If a method of `mock_foo` other than `DoThis()` is called, it will be -reported by Google Mock as a warning. However, if you rewrite your -test to use `NiceMock` instead, the warning will be gone, -resulting in a cleaner test output: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -`NiceMock` is a subclass of `MockFoo`, so it can be used -wherever `MockFoo` is accepted. - -It also works if `MockFoo`'s constructor takes some arguments, as -`NiceMock` "inherits" `MockFoo`'s constructors: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -The usage of `StrictMock` is similar, except that it makes all -uninteresting calls failures: - -``` -using ::testing::StrictMock; - -TEST(...) { - StrictMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... - - // The test will fail if a method of mock_foo other than DoThis() - // is called. -} -``` - -There are some caveats though (I don't like them just as much as the -next guy, but sadly they are side effects of C++'s limitations): - - 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. - 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). - 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) - -Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. - -## Simplifying the Interface without Breaking Existing Code ## - -Sometimes a method has a long list of arguments that is mostly -uninteresting. For example, - -``` -class LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, - const char* message, size_t message_len) = 0; -}; -``` - -This method's argument list is lengthy and hard to work with (let's -say that the `message` argument is not even 0-terminated). If we mock -it as is, using the mock will be awkward. If, however, we try to -simplify this interface, we'll need to fix all clients depending on -it, which is often infeasible. - -The trick is to re-dispatch the method in the mock class: - -``` -class ScopedMockLog : public LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const tm* tm_time, - const char* message, size_t message_len) { - // We are only interested in the log severity, full file name, and - // log message. - Log(severity, full_filename, std::string(message, message_len)); - } - - // Implements the mock method: - // - // void Log(LogSeverity severity, - // const string& file_path, - // const string& message); - MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, - const string& message)); -}; -``` - -By defining a new mock method with a trimmed argument list, we make -the mock class much more user-friendly. - -## Alternative to Mocking Concrete Classes ## - -Often you may find yourself using classes that don't implement -interfaces. In order to test your code that uses such a class (let's -call it `Concrete`), you may be tempted to make the methods of -`Concrete` virtual and then mock it. - -Try not to do that. - -Making a non-virtual function virtual is a big decision. It creates an -extension point where subclasses can tweak your class' behavior. This -weakens your control on the class because now it's harder to maintain -the class' invariants. You should make a function virtual only when -there is a valid reason for a subclass to override it. - -Mocking concrete classes directly is problematic as it creates a tight -coupling between the class and the tests - any small change in the -class may invalidate your tests and make test maintenance a pain. - -To avoid such problems, many programmers have been practicing "coding -to interfaces": instead of talking to the `Concrete` class, your code -would define an interface and talk to it. Then you implement that -interface as an adaptor on top of `Concrete`. In tests, you can easily -mock that interface to observe how your code is doing. - -This technique incurs some overhead: - - * You pay the cost of virtual function calls (usually not a problem). - * There is more abstraction for the programmers to learn. - -However, it can also bring significant benefits in addition to better -testability: - - * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. - * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. - -Some people worry that if everyone is practicing this technique, they -will end up writing lots of redundant code. This concern is totally -understandable. However, there are two reasons why it may not be the -case: - - * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. - * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. - -You need to weigh the pros and cons carefully for your particular -problem, but I'd like to assure you that the Java community has been -practicing this for a long time and it's a proven effective technique -applicable in a wide variety of situations. :-) - -## Delegating Calls to a Fake ## - -Some times you have a non-trivial fake implementation of an -interface. For example: - -``` -class Foo { - public: - virtual ~Foo() {} - virtual char DoThis(int n) = 0; - virtual void DoThat(const char* s, int* p) = 0; -}; - -class FakeFoo : public Foo { - public: - virtual char DoThis(int n) { - return (n > 0) ? '+' : - (n < 0) ? '-' : '0'; - } - - virtual void DoThat(const char* s, int* p) { - *p = strlen(s); - } -}; -``` - -Now you want to mock this interface such that you can set expectations -on it. However, you also want to use `FakeFoo` for the default -behavior, as duplicating it in the mock object is, well, a lot of -work. - -When you define the mock class using Google Mock, you can have it -delegate its default action to a fake class you already have, using -this pattern: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - // Normal mock method definitions using Google Mock. - MOCK_METHOD1(DoThis, char(int n)); - MOCK_METHOD2(DoThat, void(const char* s, int* p)); - - // Delegates the default actions of the methods to a FakeFoo object. - // This must be called *before* the custom ON_CALL() statements. - void DelegateToFake() { - ON_CALL(*this, DoThis(_)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); - ON_CALL(*this, DoThat(_, _)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); - } - private: - FakeFoo fake_; // Keeps an instance of the fake in the mock. -}; -``` - -With that, you can use `MockFoo` in your tests as usual. Just remember -that if you don't explicitly set an action in an `ON_CALL()` or -`EXPECT_CALL()`, the fake will be called upon to do it: - -``` -using ::testing::_; - -TEST(AbcTest, Xyz) { - MockFoo foo; - foo.DelegateToFake(); // Enables the fake for delegation. - - // Put your ON_CALL(foo, ...)s here, if any. - - // No action specified, meaning to use the default action. - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(foo, DoThat(_, _)); - - int n = 0; - EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. - foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. - EXPECT_EQ(2, n); -} -``` - -**Some tips:** - - * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. - * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. - * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). - * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. - -Regarding the tip on mixing a mock and a fake, here's an example on -why it may be a bad sign: Suppose you have a class `System` for -low-level system operations. In particular, it does file and I/O -operations. And suppose you want to test how your code uses `System` -to do I/O, and you just want the file operations to work normally. If -you mock out the entire `System` class, you'll have to provide a fake -implementation for the file operation part, which suggests that -`System` is taking on too many roles. - -Instead, you can define a `FileOps` interface and an `IOOps` interface -and split `System`'s functionalities into the two. Then you can mock -`IOOps` without mocking `FileOps`. - -## Delegating Calls to a Real Object ## - -When using testing doubles (mocks, fakes, stubs, and etc), sometimes -their behaviors will differ from those of the real objects. This -difference could be either intentional (as in simulating an error such -that you can test the error handling code) or unintentional. If your -mocks have different behaviors than the real objects by mistake, you -could end up with code that passes the tests but fails in production. - -You can use the _delegating-to-real_ technique to ensure that your -mock has the same behavior as the real object while retaining the -ability to validate calls. This technique is very similar to the -delegating-to-fake technique, the difference being that we use a real -object instead of a fake. Here's an example: - -``` -using ::testing::_; -using ::testing::AtLeast; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MockFoo() { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DoThis()) - .WillByDefault(Invoke(&real_, &Foo::DoThis)); - ON_CALL(*this, DoThat(_)) - .WillByDefault(Invoke(&real_, &Foo::DoThat)); - ... - } - MOCK_METHOD0(DoThis, ...); - MOCK_METHOD1(DoThat, ...); - ... - private: - Foo real_; -}; -... - - MockFoo mock; - - EXPECT_CALL(mock, DoThis()) - .Times(3); - EXPECT_CALL(mock, DoThat("Hi")) - .Times(AtLeast(1)); - ... use mock in test ... -``` - -With this, Google Mock will verify that your code made the right calls -(with the right arguments, in the right order, called the right number -of times, etc), and a real object will answer the calls (so the -behavior will be the same as in production). This gives you the best -of both worlds. - -## Delegating Calls to a Parent Class ## - -Ideally, you should code to interfaces, whose methods are all pure -virtual. In reality, sometimes you do need to mock a virtual method -that is not pure (i.e, it already has an implementation). For example: - -``` -class Foo { - public: - virtual ~Foo(); - - virtual void Pure(int n) = 0; - virtual int Concrete(const char* str) { ... } -}; - -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); -}; -``` - -Sometimes you may want to call `Foo::Concrete()` instead of -`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub -action, or perhaps your test doesn't need to mock `Concrete()` at all -(but it would be oh-so painful to have to define a new mock class -whenever you don't need to mock one of its methods). - -The trick is to leave a back door in your mock class for accessing the -real methods in the base class: - -``` -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); - - // Use this to call Concrete() defined in Foo. - int FooConcrete(const char* str) { return Foo::Concrete(str); } -}; -``` - -Now, you can call `Foo::Concrete()` inside an action by: - -``` -using ::testing::_; -using ::testing::Invoke; -... - EXPECT_CALL(foo, Concrete(_)) - .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -or tell the mock object that you don't want to mock `Concrete()`: - -``` -using ::testing::Invoke; -... - ON_CALL(foo, Concrete(_)) - .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do -that, `MockFoo::Concrete()` will be called (and cause an infinite -recursion) since `Foo::Concrete()` is virtual. That's just how C++ -works.) - -# Using Matchers # - -## Matching Argument Values Exactly ## - -You can specify exactly which arguments a mock method is expecting: - -``` -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(5)) - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", bar)); -``` - -## Using Simple Matchers ## - -You can use matchers to match arguments that have a certain property: - -``` -using ::testing::Ge; -using ::testing::NotNull; -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", NotNull())); - // The second argument must not be NULL. -``` - -A frequently used matcher is `_`, which matches anything: - -``` -using ::testing::_; -using ::testing::NotNull; -... - EXPECT_CALL(foo, DoThat(_, NotNull())); -``` - -## Combining Matchers ## - -You can build complex matchers from existing ones using `AllOf()`, -`AnyOf()`, and `Not()`: - -``` -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -... - // The argument must be > 5 and != 10. - EXPECT_CALL(foo, DoThis(AllOf(Gt(5), - Ne(10)))); - - // The first argument must not contain sub-string "blah". - EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), - NULL)); -``` - -## Casting Matchers ## - -Google Mock matchers are statically typed, meaning that the compiler -can catch your mistake if you use a matcher of the wrong type (for -example, if you use `Eq(5)` to match a `string` argument). Good for -you! - -Sometimes, however, you know what you're doing and want the compiler -to give you some slack. One example is that you have a matcher for -`long` and the argument you want to match is `int`. While the two -types aren't exactly the same, there is nothing really wrong with -using a `Matcher` to match an `int` - after all, we can first -convert the `int` argument to a `long` before giving it to the -matcher. - -To support this need, Google Mock gives you the -`SafeMatcherCast(m)` function. It casts a matcher `m` to type -`Matcher`. To ensure safety, Google Mock checks that (let `U` be the -type `m` accepts): - - 1. Type `T` can be implicitly cast to type `U`; - 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and - 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). - -The code won't compile if any of these conditions isn't met. - -Here's one example: - -``` -using ::testing::SafeMatcherCast; - -// A base class and a child class. -class Base { ... }; -class Derived : public Base { ... }; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(DoThis, void(Derived* derived)); -}; -... - - MockFoo foo; - // m is a Matcher we got from somewhere. - EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); -``` - -If you find `SafeMatcherCast(m)` too limiting, you can use a similar -function `MatcherCast(m)`. The difference is that `MatcherCast` works -as long as you can `static_cast` type `T` to type `U`. - -`MatcherCast` essentially lets you bypass C++'s type system -(`static_cast` isn't always safe as it could throw away information, -for example), so be careful not to misuse/abuse it. - -## Selecting Between Overloaded Functions ## - -If you expect an overloaded function to be called, the compiler may -need some help on which overloaded version it is. - -To disambiguate functions overloaded on the const-ness of this object, -use the `Const()` argument wrapper. - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - ... - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -... - - MockFoo foo; - Bar bar1, bar2; - EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). - .WillOnce(ReturnRef(bar1)); - EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). - .WillOnce(ReturnRef(bar2)); -``` - -(`Const()` is defined by Google Mock and returns a `const` reference -to its argument.) - -To disambiguate overloaded functions with the same number of arguments -but different argument types, you may need to specify the exact type -of a matcher, either by wrapping your matcher in `Matcher()`, or -using a matcher whose type is fixed (`TypedEq`, `An()`, -etc): - -``` -using ::testing::An; -using ::testing::Lt; -using ::testing::Matcher; -using ::testing::TypedEq; - -class MockPrinter : public Printer { - public: - MOCK_METHOD1(Print, void(int n)); - MOCK_METHOD1(Print, void(char c)); -}; - -TEST(PrinterTest, Print) { - MockPrinter printer; - - EXPECT_CALL(printer, Print(An())); // void Print(int); - EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); - EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); - - printer.Print(3); - printer.Print(6); - printer.Print('a'); -} -``` - -## Performing Different Actions Based on the Arguments ## - -When a mock method is called, the _last_ matching expectation that's -still active will be selected (think "newer overrides older"). So, you -can make a method do different things depending on its argument values -like this: - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Return; -... - // The default case. - EXPECT_CALL(foo, DoThis(_)) - .WillRepeatedly(Return('b')); - - // The more specific case. - EXPECT_CALL(foo, DoThis(Lt(5))) - .WillRepeatedly(Return('a')); -``` - -Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will -be returned; otherwise `'b'` will be returned. - -## Matching Multiple Arguments as a Whole ## - -Sometimes it's not enough to match the arguments individually. For -example, we may want to say that the first argument must be less than -the second argument. The `With()` clause allows us to match -all arguments of a mock function as a whole. For example, - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Ne; -... - EXPECT_CALL(foo, InRange(Ne(0), _)) - .With(Lt()); -``` - -says that the first argument of `InRange()` must not be 0, and must be -less than the second argument. - -The expression inside `With()` must be a matcher of type -`Matcher< ::testing::tuple >`, where `A1`, ..., `An` are the -types of the function arguments. - -You can also write `AllArgs(m)` instead of `m` inside `.With()`. The -two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable -than `.With(Lt())`. - -You can use `Args(m)` to match the `n` selected arguments -(as a tuple) against `m`. For example, - -``` -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::Lt; -... - EXPECT_CALL(foo, Blah(_, _, _)) - .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); -``` - -says that `Blah()` will be called with arguments `x`, `y`, and `z` where -`x < y < z`. - -As a convenience and example, Google Mock provides some matchers for -2-tuples, including the `Lt()` matcher above. See the [CheatSheet](CheatSheet.md) for -the complete list. - -Note that if you want to pass the arguments to a predicate of your own -(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be -written to take a `::testing::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. - -## Using Matchers as Predicates ## - -Have you noticed that a matcher is just a fancy predicate that also -knows how to describe itself? Many existing algorithms take predicates -as arguments (e.g. those defined in STL's `` header), and -it would be a shame if Google Mock matchers are not allowed to -participate. - -Luckily, you can use a matcher where a unary predicate functor is -expected by wrapping it inside the `Matches()` function. For example, - -``` -#include -#include - -std::vector v; -... -// How many elements in v are >= 10? -const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); -``` - -Since you can build complex matchers from simpler ones easily using -Google Mock, this gives you a way to conveniently construct composite -predicates (doing the same using STL's `` header is just -painful). For example, here's a predicate that's satisfied by any -number that is >= 0, <= 100, and != 50: - -``` -Matches(AllOf(Ge(0), Le(100), Ne(50))) -``` - -## Using Matchers in Google Test Assertions ## - -Since matchers are basically predicates that also know how to describe -themselves, there is a way to take advantage of them in -[Google Test](../../googletest/) assertions. It's -called `ASSERT_THAT` and `EXPECT_THAT`: - -``` - ASSERT_THAT(value, matcher); // Asserts that value matches matcher. - EXPECT_THAT(value, matcher); // The non-fatal version. -``` - -For example, in a Google Test test you can write: - -``` -#include "gmock/gmock.h" - -using ::testing::AllOf; -using ::testing::Ge; -using ::testing::Le; -using ::testing::MatchesRegex; -using ::testing::StartsWith; -... - - EXPECT_THAT(Foo(), StartsWith("Hello")); - EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); - ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); -``` - -which (as you can probably guess) executes `Foo()`, `Bar()`, and -`Baz()`, and verifies that: - - * `Foo()` returns a string that starts with `"Hello"`. - * `Bar()` returns a string that matches regular expression `"Line \\d+"`. - * `Baz()` returns a number in the range [5, 10]. - -The nice thing about these macros is that _they read like -English_. They generate informative messages too. For example, if the -first `EXPECT_THAT()` above fails, the message will be something like: - -``` -Value of: Foo() - Actual: "Hi, world!" -Expected: starts with "Hello" -``` - -**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the -[Hamcrest](https://github.com/hamcrest/) project, which adds -`assertThat()` to JUnit. - -## Using Predicates as Matchers ## - -Google Mock provides a built-in set of matchers. In case you find them -lacking, you can use an arbitray unary predicate function or functor -as a matcher - as long as the predicate accepts a value of the type -you want. You do this by wrapping the predicate inside the `Truly()` -function, for example: - -``` -using ::testing::Truly; - -int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } -... - - // Bar() must be called with an even number. - EXPECT_CALL(foo, Bar(Truly(IsEven))); -``` - -Note that the predicate function / functor doesn't have to return -`bool`. It works as long as the return value can be used as the -condition in statement `if (condition) ...`. - -## Matching Arguments that Are Not Copyable ## - -When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves -away a copy of `bar`. When `Foo()` is called later, Google Mock -compares the argument to `Foo()` with the saved copy of `bar`. This -way, you don't need to worry about `bar` being modified or destroyed -after the `EXPECT_CALL()` is executed. The same is true when you use -matchers like `Eq(bar)`, `Le(bar)`, and so on. - -But what if `bar` cannot be copied (i.e. has no copy constructor)? You -could define your own matcher function and use it with `Truly()`, as -the previous couple of recipes have shown. Or, you may be able to get -away from it if you can guarantee that `bar` won't be changed after -the `EXPECT_CALL()` is executed. Just tell Google Mock that it should -save a reference to `bar`, instead of a copy of it. Here's how: - -``` -using ::testing::Eq; -using ::testing::ByRef; -using ::testing::Lt; -... - // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); - - // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); -``` - -Remember: if you do this, don't change `bar` after the -`EXPECT_CALL()`, or the result is undefined. - -## Validating a Member of an Object ## - -Often a mock function takes a reference to object as an argument. When -matching the argument, you may not want to compare the entire object -against a fixed object, as that may be over-specification. Instead, -you may need to validate a certain member variable or the result of a -certain getter method of the object. You can do this with `Field()` -and `Property()`. More specifically, - -``` -Field(&Foo::bar, m) -``` - -is a matcher that matches a `Foo` object whose `bar` member variable -satisfies matcher `m`. - -``` -Property(&Foo::baz, m) -``` - -is a matcher that matches a `Foo` object whose `baz()` method returns -a value that satisfies matcher `m`. - -For example: - -> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | -|:-----------------------------|:-----------------------------------| -> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | - -Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no -argument and be declared as `const`. - -BTW, `Field()` and `Property()` can also match plain pointers to -objects. For instance, - -``` -Field(&Foo::number, Ge(3)) -``` - -matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, -the match will always fail regardless of the inner matcher. - -What if you want to validate more than one members at the same time? -Remember that there is `AllOf()`. - -## Validating the Value Pointed to by a Pointer Argument ## - -C++ functions often take pointers as arguments. You can use matchers -like `IsNull()`, `NotNull()`, and other comparison matchers to match a -pointer, but what if you want to make sure the value _pointed to_ by -the pointer, instead of the pointer itself, has a certain property? -Well, you can use the `Pointee(m)` matcher. - -`Pointee(m)` matches a pointer iff `m` matches the value the pointer -points to. For example: - -``` -using ::testing::Ge; -using ::testing::Pointee; -... - EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); -``` - -expects `foo.Bar()` to be called with a pointer that points to a value -greater than or equal to 3. - -One nice thing about `Pointee()` is that it treats a `NULL` pointer as -a match failure, so you can write `Pointee(m)` instead of - -``` - AllOf(NotNull(), Pointee(m)) -``` - -without worrying that a `NULL` pointer will crash your test. - -Also, did we tell you that `Pointee()` works with both raw pointers -**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and -etc)? - -What if you have a pointer to pointer? You guessed it - you can use -nested `Pointee()` to probe deeper inside the value. For example, -`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer -that points to a number less than 3 (what a mouthful...). - -## Testing a Certain Property of an Object ## - -Sometimes you want to specify that an object argument has a certain -property, but there is no existing matcher that does this. If you want -good error messages, you should define a matcher. If you want to do it -quick and dirty, you could get away with writing an ordinary function. - -Let's say you have a mock function that takes an object of type `Foo`, -which has an `int bar()` method and an `int baz()` method, and you -want to constrain that the argument's `bar()` value plus its `baz()` -value is a given number. Here's how you can define a matcher to do it: - -``` -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class BarPlusBazEqMatcher : public MatcherInterface { - public: - explicit BarPlusBazEqMatcher(int expected_sum) - : expected_sum_(expected_sum) {} - - virtual bool MatchAndExplain(const Foo& foo, - MatchResultListener* listener) const { - return (foo.bar() + foo.baz()) == expected_sum_; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "bar() + baz() equals " << expected_sum_; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "bar() + baz() does not equal " << expected_sum_; - } - private: - const int expected_sum_; -}; - -inline Matcher BarPlusBazEq(int expected_sum) { - return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); -} - -... - - EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; -``` - -## Matching Containers ## - -Sometimes an STL container (e.g. list, vector, map, ...) is passed to -a mock function and you may want to validate it. Since most STL -containers support the `==` operator, you can write -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. - -Sometimes, though, you may want to be more flexible (for example, the -first element must be an exact match, but the second element can be -any positive number, and so on). Also, containers used in tests often -have a small number of elements, and having to define the expected -container out-of-line is a bit of a hassle. - -You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in -such cases: - -``` -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::Gt; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); -``` - -The above matcher says that the container must have 4 elements, which -must be 1, greater than 0, anything, and 5 respectively. - -If you instead write: - -``` -using ::testing::_; -using ::testing::Gt; -using ::testing::UnorderedElementsAre; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); -``` - -It means that the container must have 4 elements, which under some -permutation must be 1, greater than 0, anything, and 5 respectively. - -`ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 -to 10 arguments. If more are needed, you can place them in a C-style -array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` -instead: - -``` -using ::testing::ElementsAreArray; -... - - // ElementsAreArray accepts an array of element values. - const int expected_vector1[] = { 1, 5, 2, 4, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); - - // Or, an array of element matchers. - Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); -``` - -In case the array needs to be dynamically created (and therefore the -array size cannot be inferred by the compiler), you can give -`ElementsAreArray()` an additional argument to specify the array size: - -``` -using ::testing::ElementsAreArray; -... - int* const expected_vector3 = new int[count]; - ... fill expected_vector3 with values ... - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); -``` - -**Tips:** - - * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. - * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. - * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. - * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). - -## Sharing Matchers ## - -Under the hood, a Google Mock matcher object consists of a pointer to -a ref-counted implementation object. Copying matchers is allowed and -very efficient, as only the pointer is copied. When the last matcher -that references the implementation object dies, the implementation -object will be deleted. - -Therefore, if you have some complex matcher that you want to use again -and again, there is no need to build it everytime. Just assign it to a -matcher variable and use that variable repeatedly! For example, - -``` - Matcher in_range = AllOf(Gt(5), Le(10)); - ... use in_range as a matcher in multiple EXPECT_CALLs ... -``` - -# Setting Expectations # - -## Knowing When to Expect ## - -`ON_CALL` is likely the single most under-utilized construct in Google Mock. - -There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). - -Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. - -This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? - -The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. - -Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. - -So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). - -If you are bothered by the "Uninteresting mock function call" message printed when a mock method without an `EXPECT_CALL` is called, you may use a `NiceMock` instead to suppress all such messages for the mock object, or suppress the message for specific methods by adding `EXPECT_CALL(...).Times(AnyNumber())`. DO NOT suppress it by blindly adding an `EXPECT_CALL(...)`, or you'll have a test that's a pain to maintain. - -## Ignoring Uninteresting Calls ## - -If you are not interested in how a mock method is called, just don't -say anything about it. In this case, if the method is ever called, -Google Mock will perform its default action to allow the test program -to continue. If you are not happy with the default action taken by -Google Mock, you can override it using `DefaultValue::Set()` -(described later in this document) or `ON_CALL()`. - -Please note that once you expressed interest in a particular mock -method (via `EXPECT_CALL()`), all invocations to it must match some -expectation. If this function is called but the arguments don't match -any `EXPECT_CALL()` statement, it will be an error. - -## Disallowing Unexpected Calls ## - -If a mock method shouldn't be called at all, explicitly say so: - -``` -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -If some calls to the method are allowed, but the rest are not, just -list all the expected calls: - -``` -using ::testing::AnyNumber; -using ::testing::Gt; -... - EXPECT_CALL(foo, Bar(5)); - EXPECT_CALL(foo, Bar(Gt(10))) - .Times(AnyNumber()); -``` - -A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` -statements will be an error. - -## Understanding Uninteresting vs Unexpected Calls ## - -_Uninteresting_ calls and _unexpected_ calls are different concepts in Google Mock. _Very_ different. - -A call `x.Y(...)` is **uninteresting** if there's _not even a single_ `EXPECT_CALL(x, Y(...))` set. In other words, the test isn't interested in the `x.Y()` method at all, as evident in that the test doesn't care to say anything about it. - -A call `x.Y(...)` is **unexpected** if there are some `EXPECT_CALL(x, Y(...))s` set, but none of them matches the call. Put another way, the test is interested in the `x.Y()` method (therefore it _explicitly_ sets some `EXPECT_CALL` to verify how it's called); however, the verification fails as the test doesn't expect this particular call to happen. - -**An unexpected call is always an error,** as the code under test doesn't behave the way the test expects it to behave. - -**By default, an uninteresting call is not an error,** as it violates no constraint specified by the test. (Google Mock's philosophy is that saying nothing means there is no constraint.) However, it leads to a warning, as it _might_ indicate a problem (e.g. the test author might have forgotten to specify a constraint). - -In Google Mock, `NiceMock` and `StrictMock` can be used to make a mock class "nice" or "strict". How does this affect uninteresting calls and unexpected calls? - -A **nice mock** suppresses uninteresting call warnings. It is less chatty than the default mock, but otherwise is the same. If a test fails with a default mock, it will also fail using a nice mock instead. And vice versa. Don't expect making a mock nice to change the test's result. - -A **strict mock** turns uninteresting call warnings into errors. So making a mock strict may change the test's result. - -Let's look at an example: - -``` -TEST(...) { - NiceMock mock_registry; - EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) - .WillRepeatedly(Return("Larry Page")); - - // Use mock_registry in code under test. - ... &mock_registry ... -} -``` - -The sole `EXPECT_CALL` here says that all calls to `GetDomainOwner()` must have `"google.com"` as the argument. If `GetDomainOwner("yahoo.com")` is called, it will be an unexpected call, and thus an error. Having a nice mock doesn't change the severity of an unexpected call. - -So how do we tell Google Mock that `GetDomainOwner()` can be called with some other arguments as well? The standard technique is to add a "catch all" `EXPECT_CALL`: - -``` - EXPECT_CALL(mock_registry, GetDomainOwner(_)) - .Times(AnyNumber()); // catches all other calls to this method. - EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) - .WillRepeatedly(Return("Larry Page")); -``` - -Remember that `_` is the wildcard matcher that matches anything. With this, if `GetDomainOwner("google.com")` is called, it will do what the second `EXPECT_CALL` says; if it is called with a different argument, it will do what the first `EXPECT_CALL` says. - -Note that the order of the two `EXPECT_CALLs` is important, as a newer `EXPECT_CALL` takes precedence over an older one. - -For more on uninteresting calls, nice mocks, and strict mocks, read ["The Nice, the Strict, and the Naggy"](#the-nice-the-strict-and-the-naggy). - -## Expecting Ordered Calls ## - -Although an `EXPECT_CALL()` statement defined earlier takes precedence -when Google Mock tries to match a function call with an expectation, -by default calls don't have to happen in the order `EXPECT_CALL()` -statements are written. For example, if the arguments match the -matchers in the third `EXPECT_CALL()`, but not those in the first two, -then the third expectation will be used. - -If you would rather have all calls occur in the order of the -expectations, put the `EXPECT_CALL()` statements in a block where you -define a variable of type `InSequence`: - -``` - using ::testing::_; - using ::testing::InSequence; - - { - InSequence s; - - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(bar, DoThat(_)) - .Times(2); - EXPECT_CALL(foo, DoThis(6)); - } -``` - -In this example, we expect a call to `foo.DoThis(5)`, followed by two -calls to `bar.DoThat()` where the argument can be anything, which are -in turn followed by a call to `foo.DoThis(6)`. If a call occurred -out-of-order, Google Mock will report an error. - -## Expecting Partially Ordered Calls ## - -Sometimes requiring everything to occur in a predetermined order can -lead to brittle tests. For example, we may care about `A` occurring -before both `B` and `C`, but aren't interested in the relative order -of `B` and `C`. In this case, the test should reflect our real intent, -instead of being overly constraining. - -Google Mock allows you to impose an arbitrary DAG (directed acyclic -graph) on the calls. One way to express the DAG is to use the -[After](CheatSheet.md#the-after-clause) clause of `EXPECT_CALL`. - -Another way is via the `InSequence()` clause (not the same as the -`InSequence` class), which we borrowed from jMock 2. It's less -flexible than `After()`, but more convenient when you have long chains -of sequential calls, as it doesn't require you to come up with -different names for the expectations in the chains. Here's how it -works: - -If we view `EXPECT_CALL()` statements as nodes in a graph, and add an -edge from node A to node B wherever A must occur before B, we can get -a DAG. We use the term "sequence" to mean a directed path in this -DAG. Now, if we decompose the DAG into sequences, we just need to know -which sequences each `EXPECT_CALL()` belongs to in order to be able to -reconstruct the orginal DAG. - -So, to specify the partial order on the expectations we need to do two -things: first to define some `Sequence` objects, and then for each -`EXPECT_CALL()` say which `Sequence` objects it is part -of. Expectations in the same sequence must occur in the order they are -written. For example, - -``` - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(foo, A()) - .InSequence(s1, s2); - EXPECT_CALL(bar, B()) - .InSequence(s1); - EXPECT_CALL(bar, C()) - .InSequence(s2); - EXPECT_CALL(foo, D()) - .InSequence(s2); -``` - -specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> -C -> D`): - -``` - +---> B - | - A ---| - | - +---> C ---> D -``` - -This means that A must occur before B and C, and C must occur before -D. There's no restriction about the order other than these. - -## Controlling When an Expectation Retires ## - -When a mock method is called, Google Mock only consider expectations -that are still active. An expectation is active when created, and -becomes inactive (aka _retires_) when a call that has to occur later -has occurred. For example, in - -``` - using ::testing::_; - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 - .Times(AnyNumber()) - .InSequence(s1, s2); - EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 - .InSequence(s1); - EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 - .InSequence(s2); -``` - -as soon as either #2 or #3 is matched, #1 will retire. If a warning -`"File too large."` is logged after this, it will be an error. - -Note that an expectation doesn't retire automatically when it's -saturated. For example, - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 -``` - -says that there will be exactly one warning with the message `"File -too large."`. If the second warning contains this message too, #2 will -match again and result in an upper-bound-violated error. - -If this is not what you want, you can ask an expectation to retire as -soon as it becomes saturated: - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 - .RetiresOnSaturation(); -``` - -Here #2 can be used only once, so if you have two warnings with the -message `"File too large."`, the first will match #2 and the second -will match #1 - there will be no error. - -# Using Actions # - -## Returning References from Mock Methods ## - -If a mock function's return type is a reference, you need to use -`ReturnRef()` instead of `Return()` to return a result: - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetBar, Bar&()); -}; -... - - MockFoo foo; - Bar bar; - EXPECT_CALL(foo, GetBar()) - .WillOnce(ReturnRef(bar)); -``` - -## Returning Live Values from Mock Methods ## - -The `Return(x)` action saves a copy of `x` when the action is -_created_, and always returns the same value whenever it's -executed. Sometimes you may want to instead return the _live_ value of -`x` (i.e. its value at the time when the action is _executed_.). - -If the mock function's return type is a reference, you can do it using -`ReturnRef(x)`, as shown in the previous recipe ("Returning References -from Mock Methods"). However, Google Mock doesn't let you use -`ReturnRef()` in a mock function whose return type is not a reference, -as doing that usually indicates a user error. So, what shall you do? - -You may be tempted to try `ByRef()`: - -``` -using testing::ByRef; -using testing::Return; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetValue, int()); -}; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(Return(ByRef(x))); - x = 42; - EXPECT_EQ(42, foo.GetValue()); -``` - -Unfortunately, it doesn't work here. The above code will fail with error: - -``` -Value of: foo.GetValue() - Actual: 0 -Expected: 42 -``` - -The reason is that `Return(value)` converts `value` to the actual -return type of the mock function at the time when the action is -_created_, not when it is _executed_. (This behavior was chosen for -the action to be safe when `value` is a proxy object that references -some temporary objects.) As a result, `ByRef(x)` is converted to an -`int` value (instead of a `const int&`) when the expectation is set, -and `Return(ByRef(x))` will always return 0. - -`ReturnPointee(pointer)` was provided to solve this problem -specifically. It returns the value pointed to by `pointer` at the time -the action is _executed_: - -``` -using testing::ReturnPointee; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(ReturnPointee(&x)); // Note the & here. - x = 42; - EXPECT_EQ(42, foo.GetValue()); // This will succeed now. -``` - -## Combining Actions ## - -Want to do more than one thing when a function is called? That's -fine. `DoAll()` allow you to do sequence of actions every time. Only -the return value of the last action in the sequence will be used. - -``` -using ::testing::DoAll; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Bar, bool(int n)); -}; -... - - EXPECT_CALL(foo, Bar(_)) - .WillOnce(DoAll(action_1, - action_2, - ... - action_n)); -``` - -## Mocking Side Effects ## - -Sometimes a method exhibits its effect not via returning a value but -via side effects. For example, it may change some global state or -modify an output argument. To mock side effects, in general you can -define your own action by implementing `::testing::ActionInterface`. - -If all you need to do is to change an output argument, the built-in -`SetArgPointee()` action is convenient: - -``` -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - MOCK_METHOD2(Mutate, void(bool mutate, int* value)); - ... -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, Mutate(true, _)) - .WillOnce(SetArgPointee<1>(5)); -``` - -In this example, when `mutator.Mutate()` is called, we will assign 5 -to the `int` variable pointed to by argument #1 -(0-based). - -`SetArgPointee()` conveniently makes an internal copy of the -value you pass to it, removing the need to keep the value in scope and -alive. The implication however is that the value must have a copy -constructor and assignment operator. - -If the mock method also needs to return a value as well, you can chain -`SetArgPointee()` with `Return()` using `DoAll()`: - -``` -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - ... - MOCK_METHOD1(MutateInt, bool(int* value)); -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, MutateInt(_)) - .WillOnce(DoAll(SetArgPointee<0>(5), - Return(true))); -``` - -If the output argument is an array, use the -`SetArrayArgument(first, last)` action instead. It copies the -elements in source range `[first, last)` to the array pointed to by -the `N`-th (0-based) argument: - -``` -using ::testing::NotNull; -using ::testing::SetArrayArgument; - -class MockArrayMutator : public ArrayMutator { - public: - MOCK_METHOD2(Mutate, void(int* values, int num_values)); - ... -}; -... - - MockArrayMutator mutator; - int values[5] = { 1, 2, 3, 4, 5 }; - EXPECT_CALL(mutator, Mutate(NotNull(), 5)) - .WillOnce(SetArrayArgument<0>(values, values + 5)); -``` - -This also works when the argument is an output iterator: - -``` -using ::testing::_; -using ::testing::SeArrayArgument; - -class MockRolodex : public Rolodex { - public: - MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); - ... -}; -... - - MockRolodex rolodex; - vector names; - names.push_back("George"); - names.push_back("John"); - names.push_back("Thomas"); - EXPECT_CALL(rolodex, GetNames(_)) - .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); -``` - -## Changing a Mock Object's Behavior Based on the State ## - -If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: - -``` -using ::testing::InSequence; -using ::testing::Return; - -... - { - InSequence seq; - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(my_mock, Flush()); - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(false)); - } - my_mock.FlushIfDirty(); -``` - -This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. - -If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: - -``` -using ::testing::_; -using ::testing::SaveArg; -using ::testing::Return; - -ACTION_P(ReturnPointee, p) { return *p; } -... - int previous_value = 0; - EXPECT_CALL(my_mock, GetPrevValue()) - .WillRepeatedly(ReturnPointee(&previous_value)); - EXPECT_CALL(my_mock, UpdateValue(_)) - .WillRepeatedly(SaveArg<0>(&previous_value)); - my_mock.DoSomethingToUpdateValue(); -``` - -Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. - -## Setting the Default Value for a Return Type ## - -If a mock method's return type is a built-in C++ type or pointer, by -default it will return 0 when invoked. Also, in C++ 11 and above, a mock -method whose return type has a default constructor will return a default-constructed -value by default. You only need to specify an -action if this default value doesn't work for you. - -Sometimes, you may want to change this default value, or you may want -to specify a default value for types Google Mock doesn't know -about. You can do this using the `::testing::DefaultValue` class -template: - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD0(CalculateBar, Bar()); -}; -... - - Bar default_bar; - // Sets the default return value for type Bar. - DefaultValue::Set(default_bar); - - MockFoo foo; - - // We don't need to specify an action here, as the default - // return value works for us. - EXPECT_CALL(foo, CalculateBar()); - - foo.CalculateBar(); // This should return default_bar. - - // Unsets the default return value. - DefaultValue::Clear(); -``` - -Please note that changing the default value for a type can make you -tests hard to understand. We recommend you to use this feature -judiciously. For example, you may want to make sure the `Set()` and -`Clear()` calls are right next to the code that uses your mock. - -## Setting the Default Actions for a Mock Method ## - -You've learned how to change the default value of a given -type. However, this may be too coarse for your purpose: perhaps you -have two mock methods with the same return type and you want them to -have different behaviors. The `ON_CALL()` macro allows you to -customize your mock's behavior at the method level: - -``` -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Gt; -using ::testing::Return; -... - ON_CALL(foo, Sign(_)) - .WillByDefault(Return(-1)); - ON_CALL(foo, Sign(0)) - .WillByDefault(Return(0)); - ON_CALL(foo, Sign(Gt(0))) - .WillByDefault(Return(1)); - - EXPECT_CALL(foo, Sign(_)) - .Times(AnyNumber()); - - foo.Sign(5); // This should return 1. - foo.Sign(-9); // This should return -1. - foo.Sign(0); // This should return 0. -``` - -As you may have guessed, when there are more than one `ON_CALL()` -statements, the news order take precedence over the older ones. In -other words, the **last** one that matches the function arguments will -be used. This matching order allows you to set up the common behavior -in a mock object's constructor or the test fixture's set-up phase and -specialize the mock's behavior later. - -## Using Functions/Methods/Functors as Actions ## - -If the built-in actions don't suit you, you can easily use an existing -function, method, or functor as an action: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(Sum, int(int x, int y)); - MOCK_METHOD1(ComplexJob, bool(int x)); -}; - -int CalculateSum(int x, int y) { return x + y; } - -class Helper { - public: - bool ComplexJob(int x); -}; -... - - MockFoo foo; - Helper helper; - EXPECT_CALL(foo, Sum(_, _)) - .WillOnce(Invoke(CalculateSum)); - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(Invoke(&helper, &Helper::ComplexJob)); - - foo.Sum(5, 6); // Invokes CalculateSum(5, 6). - foo.ComplexJob(10); // Invokes helper.ComplexJob(10); -``` - -The only requirement is that the type of the function, etc must be -_compatible_ with the signature of the mock function, meaning that the -latter's arguments can be implicitly converted to the corresponding -arguments of the former, and the former's return type can be -implicitly converted to that of the latter. So, you can invoke -something whose type is _not_ exactly the same as the mock function, -as long as it's safe to do so - nice, huh? - -## Invoking a Function/Method/Functor Without Arguments ## - -`Invoke()` is very useful for doing actions that are more complex. It -passes the mock function's arguments to the function or functor being -invoked such that the callee has the full context of the call to work -with. If the invoked function is not interested in some or all of the -arguments, it can simply ignore them. - -Yet, a common pattern is that a test author wants to invoke a function -without the arguments of the mock function. `Invoke()` allows her to -do that using a wrapper function that throws away the arguments before -invoking an underlining nullary function. Needless to say, this can be -tedious and obscures the intent of the test. - -`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except -that it doesn't pass the mock function's arguments to the -callee. Here's an example: - -``` -using ::testing::_; -using ::testing::InvokeWithoutArgs; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(ComplexJob, bool(int n)); -}; - -bool Job1() { ... } -... - - MockFoo foo; - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(InvokeWithoutArgs(Job1)); - - foo.ComplexJob(10); // Invokes Job1(). -``` - -## Invoking an Argument of the Mock Function ## - -Sometimes a mock function will receive a function pointer or a functor -(in other words, a "callable") as an argument, e.g. - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); -}; -``` - -and you may want to invoke this callable argument: - -``` -using ::testing::_; -... - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(...); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -Arghh, you need to refer to a mock function argument but C++ has no -lambda (yet), so you have to define your own action. :-( Or do you -really? - -Well, Google Mock has an action to solve _exactly_ this problem: - -``` - InvokeArgument(arg_1, arg_2, ..., arg_m) -``` - -will invoke the `N`-th (0-based) argument the mock function receives, -with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is -a function pointer or a functor, Google Mock handles them both. - -With that, you could write: - -``` -using ::testing::_; -using ::testing::InvokeArgument; -... - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(InvokeArgument<1>(5)); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -What if the callable takes an argument by reference? No problem - just -wrap it inside `ByRef()`: - -``` -... - MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); -... -using ::testing::_; -using ::testing::ByRef; -using ::testing::InvokeArgument; -... - - MockFoo foo; - Helper helper; - ... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, ByRef(helper))); - // ByRef(helper) guarantees that a reference to helper, not a copy of it, - // will be passed to the callable. -``` - -What if the callable takes an argument by reference and we do **not** -wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a -copy_ of the argument, and pass a _reference to the copy_, instead of -a reference to the original value, to the callable. This is especially -handy when the argument is a temporary value: - -``` -... - MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); -... -using ::testing::_; -using ::testing::InvokeArgument; -... - - MockFoo foo; - ... - EXPECT_CALL(foo, DoThat(_)) - .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); - // Will execute (*f)(5.0, string("Hi")), where f is the function pointer - // DoThat() receives. Note that the values 5.0 and string("Hi") are - // temporary and dead once the EXPECT_CALL() statement finishes. Yet - // it's fine to perform this action later, since a copy of the values - // are kept inside the InvokeArgument action. -``` - -## Ignoring an Action's Result ## - -Sometimes you have an action that returns _something_, but you need an -action that returns `void` (perhaps you want to use it in a mock -function that returns `void`, or perhaps it needs to be used in -`DoAll()` and it's not the last in the list). `IgnoreResult()` lets -you do that. For example: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; - -int Process(const MyData& data); -string DoSomething(); - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Abc, void(const MyData& data)); - MOCK_METHOD0(Xyz, bool()); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, Abc(_)) - // .WillOnce(Invoke(Process)); - // The above line won't compile as Process() returns int but Abc() needs - // to return void. - .WillOnce(IgnoreResult(Invoke(Process))); - - EXPECT_CALL(foo, Xyz()) - .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), - // Ignores the string DoSomething() returns. - Return(true))); -``` - -Note that you **cannot** use `IgnoreResult()` on an action that already -returns `void`. Doing so will lead to ugly compiler errors. - -## Selecting an Action's Arguments ## - -Say you have a mock function `Foo()` that takes seven arguments, and -you have a custom action that you want to invoke when `Foo()` is -called. Trouble is, the custom action only wants three arguments: - -``` -using ::testing::_; -using ::testing::Invoke; -... - MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight)); -... - -bool IsVisibleInQuadrant1(bool visible, int x, int y) { - return visible && x >= 0 && y >= 0; -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( -``` - -To please the compiler God, you can to define an "adaptor" that has -the same signature as `Foo()` and calls the custom action with the -right arguments: - -``` -using ::testing::_; -using ::testing::Invoke; - -bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight) { - return IsVisibleInQuadrant1(visible, x, y); -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. -``` - -But isn't this awkward? - -Google Mock provides a generic _action adaptor_, so you can spend your -time minding more important business than writing your own -adaptors. Here's the syntax: - -``` - WithArgs(action) -``` - -creates an action that passes the arguments of the mock function at -the given indices (0-based) to the inner `action` and performs -it. Using `WithArgs`, our original example can be written as: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::WithArgs; -... - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); - // No need to define your own adaptor. -``` - -For better readability, Google Mock also gives you: - - * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and - * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. - -As you may have realized, `InvokeWithoutArgs(...)` is just syntactic -sugar for `WithoutArgs(Invoke(...))`. - -Here are more tips: - - * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. - * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. - * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. - * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. - -## Ignoring Arguments in Action Functions ## - -The selecting-an-action's-arguments recipe showed us one way to make a -mock function and an action with incompatible argument lists fit -together. The downside is that wrapping the action in -`WithArgs<...>()` can get tedious for people writing the tests. - -If you are defining a function, method, or functor to be used with -`Invoke*()`, and you are not interested in some of its arguments, an -alternative to `WithArgs` is to declare the uninteresting arguments as -`Unused`. This makes the definition less cluttered and less fragile in -case the types of the uninteresting arguments change. It could also -increase the chance the action function can be reused. For example, -given - -``` - MOCK_METHOD3(Foo, double(const string& label, double x, double y)); - MOCK_METHOD3(Bar, double(int index, double x, double y)); -``` - -instead of - -``` -using ::testing::_; -using ::testing::Invoke; - -double DistanceToOriginWithLabel(const string& label, double x, double y) { - return sqrt(x*x + y*y); -} - -double DistanceToOriginWithIndex(int index, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOriginWithLabel)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOriginWithIndex)); -``` - -you could write - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Unused; - -double DistanceToOrigin(Unused, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOrigin)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOrigin)); -``` - -## Sharing Actions ## - -Just like matchers, a Google Mock action object consists of a pointer -to a ref-counted implementation object. Therefore copying actions is -also allowed and very efficient. When the last action that references -the implementation object dies, the implementation object will be -deleted. - -If you have some complex action that you want to use again and again, -you may not have to build it from scratch everytime. If the action -doesn't have an internal state (i.e. if it always does the same thing -no matter how many times it has been called), you can assign it to an -action variable and use that variable repeatedly. For example: - -``` - Action set_flag = DoAll(SetArgPointee<0>(5), - Return(true)); - ... use set_flag in .WillOnce() and .WillRepeatedly() ... -``` - -However, if the action has its own state, you may be surprised if you -share the action object. Suppose you have an action factory -`IncrementCounter(init)` which creates an action that increments and -returns a counter whose initial value is `init`, using two actions -created from the same expression and using a shared action will -exihibit different behaviors. Example: - -``` - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(IncrementCounter(0)); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(IncrementCounter(0)); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 1 - Blah() uses a different - // counter than Bar()'s. -``` - -versus - -``` - Action increment = IncrementCounter(0); - - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(increment); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(increment); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 3 - the counter is shared. -``` - -# Misc Recipes on Using Google Mock # - -## Mocking Methods That Use Move-Only Types ## - -C++11 introduced move-only types. A move-only-typed value can be moved from one object to another, but cannot be copied. `std::unique_ptr` is probably the most commonly used move-only type. - -Mocking a method that takes and/or returns move-only types presents some challenges, but nothing insurmountable. This recipe shows you how you can do it. - -Let’s say we are working on a fictional project that lets one post and share snippets called “buzzes”. Your code uses these types: - -``` -enum class AccessLevel { kInternal, kPublic }; - -class Buzz { - public: - explicit Buzz(AccessLevel access) { … } - ... -}; - -class Buzzer { - public: - virtual ~Buzzer() {} - virtual std::unique_ptr MakeBuzz(const std::string& text) = 0; - virtual bool ShareBuzz(std::unique_ptr buzz, Time timestamp) = 0; - ... -}; -``` - -A `Buzz` object represents a snippet being posted. A class that implements the `Buzzer` interface is capable of creating and sharing `Buzz`. Methods in `Buzzer` may return a `unique_ptr` or take a `unique_ptr`. Now we need to mock `Buzzer` in our tests. - -To mock a method that returns a move-only type, you just use the familiar `MOCK_METHOD` syntax as usual: - -``` -class MockBuzzer : public Buzzer { - public: - MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); - … -}; -``` - -However, if you attempt to use the same `MOCK_METHOD` pattern to mock a method that takes a move-only parameter, you’ll get a compiler error currently: - -``` - // Does NOT compile! - MOCK_METHOD2(ShareBuzz, bool(std::unique_ptr buzz, Time timestamp)); -``` - -While it’s highly desirable to make this syntax just work, it’s not trivial and the work hasn’t been done yet. Fortunately, there is a trick you can apply today to get something that works nearly as well as this. - -The trick, is to delegate the `ShareBuzz()` method to a mock method (let’s call it `DoShareBuzz()`) that does not take move-only parameters: - -``` -class MockBuzzer : public Buzzer { - public: - MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); - MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); - bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { - return DoShareBuzz(buzz.get(), timestamp); - } -}; -``` - -Note that there's no need to define or declare `DoShareBuzz()` in a base class. You only need to define it as a `MOCK_METHOD` in the mock class. - -Now that we have the mock class defined, we can use it in tests. In the following code examples, we assume that we have defined a `MockBuzzer` object named `mock_buzzer_`: - -``` - MockBuzzer mock_buzzer_; -``` - -First let’s see how we can set expectations on the `MakeBuzz()` method, which returns a `unique_ptr`. - -As usual, if you set an expectation without an action (i.e. the `.WillOnce()` or `.WillRepeated()` clause), when that expectation fires, the default action for that method will be taken. Since `unique_ptr<>` has a default constructor that returns a null `unique_ptr`, that’s what you’ll get if you don’t specify an action: - -``` - // Use the default action. - EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")); - - // Triggers the previous EXPECT_CALL. - EXPECT_EQ(nullptr, mock_buzzer_.MakeBuzz("hello")); -``` - -If you are not happy with the default action, you can tweak it. Depending on what you need, you may either tweak the default action for a specific (mock object, mock method) combination using `ON_CALL()`, or you may tweak the default action for all mock methods that return a specific type. The usage of `ON_CALL()` is similar to `EXPECT_CALL()`, so we’ll skip it and just explain how to do the latter (tweaking the default action for a specific return type). You do this via the `DefaultValue<>::SetFactory()` and `DefaultValue<>::Clear()` API: - -``` - // Sets the default action for return type std::unique_ptr to - // creating a new Buzz every time. - DefaultValue>::SetFactory( - [] { return MakeUnique(AccessLevel::kInternal); }); - - // When this fires, the default action of MakeBuzz() will run, which - // will return a new Buzz object. - EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber()); - - auto buzz1 = mock_buzzer_.MakeBuzz("hello"); - auto buzz2 = mock_buzzer_.MakeBuzz("hello"); - EXPECT_NE(nullptr, buzz1); - EXPECT_NE(nullptr, buzz2); - EXPECT_NE(buzz1, buzz2); - - // Resets the default action for return type std::unique_ptr, - // to avoid interfere with other tests. - DefaultValue>::Clear(); -``` - -What if you want the method to do something other than the default action? If you just need to return a pre-defined move-only value, you can use the `Return(ByMove(...))` action: - -``` - // When this fires, the unique_ptr<> specified by ByMove(...) will - // be returned. - EXPECT_CALL(mock_buzzer_, MakeBuzz("world")) - .WillOnce(Return(ByMove(MakeUnique(AccessLevel::kInternal)))); - - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("world")); -``` - -Note that `ByMove()` is essential here - if you drop it, the code won’t compile. - -Quiz time! What do you think will happen if a `Return(ByMove(...))` action is performed more than once (e.g. you write `….WillRepeatedly(Return(ByMove(...)));`)? Come think of it, after the first time the action runs, the source value will be consumed (since it’s a move-only value), so the next time around, there’s no value to move from -- you’ll get a run-time error that `Return(ByMove(...))` can only be run once. - -If you need your mock method to do more than just moving a pre-defined value, remember that you can always use `Invoke()` to call a lambda or a callable object, which can do pretty much anything you want: - -``` - EXPECT_CALL(mock_buzzer_, MakeBuzz("x")) - .WillRepeatedly(Invoke([](const std::string& text) { - return std::make_unique(AccessLevel::kInternal); - })); - - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); -``` - -Every time this `EXPECT_CALL` fires, a new `unique_ptr` will be created and returned. You cannot do this with `Return(ByMove(...))`. - -Now there’s one topic we haven’t covered: how do you set expectations on `ShareBuzz()`, which takes a move-only-typed parameter? The answer is you don’t. Instead, you set expectations on the `DoShareBuzz()` mock method (remember that we defined a `MOCK_METHOD` for `DoShareBuzz()`, not `ShareBuzz()`): - -``` - EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)); - - // When one calls ShareBuzz() on the MockBuzzer like this, the call is - // forwarded to DoShareBuzz(), which is mocked. Therefore this statement - // will trigger the above EXPECT_CALL. - mock_buzzer_.ShareBuzz(MakeUnique<Buzz>(AccessLevel::kInternal), - ::base::Now()); -``` - -Some of you may have spotted one problem with this approach: the `DoShareBuzz()` mock method differs from the real `ShareBuzz()` method in that it cannot take ownership of the buzz parameter - `ShareBuzz()` will always delete buzz after `DoShareBuzz()` returns. What if you need to save the buzz object somewhere for later use when `ShareBuzz()` is called? Indeed, you'd be stuck. - -Another problem with the `DoShareBuzz()` we had is that it can surprise people reading or maintaining the test, as one would expect that `DoShareBuzz()` has (logically) the same contract as `ShareBuzz()`. - -Fortunately, these problems can be fixed with a bit more code. Let's try to get it right this time: - -``` -class MockBuzzer : public Buzzer { - public: - MockBuzzer() { - // Since DoShareBuzz(buzz, time) is supposed to take ownership of - // buzz, define a default behavior for DoShareBuzz(buzz, time) to - // delete buzz. - ON_CALL(*this, DoShareBuzz(_, _)) - .WillByDefault(Invoke([](Buzz* buzz, Time timestamp) { - delete buzz; - return true; - })); - } - - MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); - - // Takes ownership of buzz. - MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); - bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { - return DoShareBuzz(buzz.release(), timestamp); - } -}; -``` - -Now, the mock `DoShareBuzz()` method is free to save the buzz argument for later use if this is what you want: - -``` - std::unique_ptr intercepted_buzz; - EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)) - .WillOnce(Invoke([&intercepted_buzz](Buzz* buzz, Time timestamp) { - // Save buzz in intercepted_buzz for analysis later. - intercepted_buzz.reset(buzz); - return false; - })); - - mock_buzzer_.ShareBuzz(std::make_unique(AccessLevel::kInternal), - Now()); - EXPECT_NE(nullptr, intercepted_buzz); -``` - -Using the tricks covered in this recipe, you are now able to mock methods that take and/or return move-only types. Put your newly-acquired power to good use - when you design a new API, you can now feel comfortable using `unique_ptrs` as appropriate, without fearing that doing so will compromise your tests. - -## Making the Compilation Faster ## - -Believe it or not, the _vast majority_ of the time spent on compiling -a mock class is in generating its constructor and destructor, as they -perform non-trivial tasks (e.g. verification of the -expectations). What's more, mock methods with different signatures -have different types and thus their constructors/destructors need to -be generated by the compiler separately. As a result, if you mock many -different types of methods, compiling your mock class can get really -slow. - -If you are experiencing slow compilation, you can move the definition -of your mock class' constructor and destructor out of the class body -and into a `.cpp` file. This way, even if you `#include` your mock -class in N files, the compiler only needs to generate its constructor -and destructor once, resulting in a much faster compilation. - -Let's illustrate the idea using an example. Here's the definition of a -mock class before applying this recipe: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // Since we don't declare the constructor or the destructor, - // the compiler will generate them in every translation unit - // where this mock class is used. - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` - -After the change, it would look like: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // The constructor and destructor are declared, but not defined, here. - MockFoo(); - virtual ~MockFoo(); - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` -and -``` -// File mock_foo.cpp. -#include "path/to/mock_foo.h" - -// The definitions may appear trivial, but the functions actually do a -// lot of things through the constructors/destructors of the member -// variables used to implement the mock methods. -MockFoo::MockFoo() {} -MockFoo::~MockFoo() {} -``` - -## Forcing a Verification ## - -When it's being destoyed, your friendly mock object will automatically -verify that all expectations on it have been satisfied, and will -generate [Google Test](../../googletest/) failures -if not. This is convenient as it leaves you with one less thing to -worry about. That is, unless you are not sure if your mock object will -be destoyed. - -How could it be that your mock object won't eventually be destroyed? -Well, it might be created on the heap and owned by the code you are -testing. Suppose there's a bug in that code and it doesn't delete the -mock object properly - you could end up with a passing test when -there's actually a bug. - -Using a heap checker is a good idea and can alleviate the concern, but -its implementation may not be 100% reliable. So, sometimes you do want -to _force_ Google Mock to verify a mock object before it is -(hopefully) destructed. You can do this with -`Mock::VerifyAndClearExpectations(&mock_object)`: - -``` -TEST(MyServerTest, ProcessesRequest) { - using ::testing::Mock; - - MockFoo* const foo = new MockFoo; - EXPECT_CALL(*foo, ...)...; - // ... other expectations ... - - // server now owns foo. - MyServer server(foo); - server.ProcessRequest(...); - - // In case that server's destructor will forget to delete foo, - // this will verify the expectations anyway. - Mock::VerifyAndClearExpectations(foo); -} // server is destroyed when it goes out of scope here. -``` - -**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a -`bool` to indicate whether the verification was successful (`true` for -yes), so you can wrap that function call inside a `ASSERT_TRUE()` if -there is no point going further when the verification has failed. - -## Using Check Points ## - -Sometimes you may want to "reset" a mock object at various check -points in your test: at each check point, you verify that all existing -expectations on the mock object have been satisfied, and then you set -some new expectations on it as if it's newly created. This allows you -to work with a mock object in "phases" whose sizes are each -manageable. - -One such scenario is that in your test's `SetUp()` function, you may -want to put the object you are testing into a certain state, with the -help from a mock object. Once in the desired state, you want to clear -all expectations on the mock, such that in the `TEST_F` body you can -set fresh expectations on it. - -As you may have figured out, the `Mock::VerifyAndClearExpectations()` -function we saw in the previous recipe can help you here. Or, if you -are using `ON_CALL()` to set default actions on the mock object and -want to clear the default actions as well, use -`Mock::VerifyAndClear(&mock_object)` instead. This function does what -`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the -same `bool`, **plus** it clears the `ON_CALL()` statements on -`mock_object` too. - -Another trick you can use to achieve the same effect is to put the -expectations in sequences and insert calls to a dummy "check-point" -function at specific places. Then you can verify that the mock -function calls do happen at the right time. For example, if you are -exercising code: - -``` -Foo(1); -Foo(2); -Foo(3); -``` - -and want to verify that `Foo(1)` and `Foo(3)` both invoke -`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: - -``` -using ::testing::MockFunction; - -TEST(FooTest, InvokesBarCorrectly) { - MyMock mock; - // Class MockFunction has exactly one mock method. It is named - // Call() and has type F. - MockFunction check; - { - InSequence s; - - EXPECT_CALL(mock, Bar("a")); - EXPECT_CALL(check, Call("1")); - EXPECT_CALL(check, Call("2")); - EXPECT_CALL(mock, Bar("a")); - } - Foo(1); - check.Call("1"); - Foo(2); - check.Call("2"); - Foo(3); -} -``` - -The expectation spec says that the first `Bar("a")` must happen before -check point "1", the second `Bar("a")` must happen after check point "2", -and nothing should happen between the two check points. The explicit -check points make it easy to tell which `Bar("a")` is called by which -call to `Foo()`. - -## Mocking Destructors ## - -Sometimes you want to make sure a mock object is destructed at the -right time, e.g. after `bar->A()` is called but before `bar->B()` is -called. We already know that you can specify constraints on the order -of mock function calls, so all we need to do is to mock the destructor -of the mock function. - -This sounds simple, except for one problem: a destructor is a special -function with special syntax and special semantics, and the -`MOCK_METHOD0` macro doesn't work for it: - -``` - MOCK_METHOD0(~MockFoo, void()); // Won't compile! -``` - -The good news is that you can use a simple pattern to achieve the same -effect. First, add a mock function `Die()` to your mock class and call -it in the destructor, like this: - -``` -class MockFoo : public Foo { - ... - // Add the following two lines to the mock class. - MOCK_METHOD0(Die, void()); - virtual ~MockFoo() { Die(); } -}; -``` - -(If the name `Die()` clashes with an existing symbol, choose another -name.) Now, we have translated the problem of testing when a `MockFoo` -object dies to testing when its `Die()` method is called: - -``` - MockFoo* foo = new MockFoo; - MockBar* bar = new MockBar; - ... - { - InSequence s; - - // Expects *foo to die after bar->A() and before bar->B(). - EXPECT_CALL(*bar, A()); - EXPECT_CALL(*foo, Die()); - EXPECT_CALL(*bar, B()); - } -``` - -And that's that. - -## Using Google Mock and Threads ## - -**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on -platforms where Google Mock is thread-safe. Currently these are only -platforms that support the pthreads library (this includes Linux and Mac). -To make it thread-safe on other platforms we only need to implement -some synchronization operations in `"gtest/internal/gtest-port.h"`. - -In a **unit** test, it's best if you could isolate and test a piece of -code in a single-threaded context. That avoids race conditions and -dead locks, and makes debugging your test much easier. - -Yet many programs are multi-threaded, and sometimes to test something -we need to pound on it from more than one thread. Google Mock works -for this purpose too. - -Remember the steps for using a mock: - - 1. Create a mock object `foo`. - 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. - 1. The code under test calls methods of `foo`. - 1. Optionally, verify and reset the mock. - 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. - -If you follow the following simple rules, your mocks and threads can -live happily together: - - * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. - * Obviously, you can do step #1 without locking. - * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? - * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. - -If you violate the rules (for example, if you set expectations on a -mock while another thread is calling its methods), you get undefined -behavior. That's not fun, so don't do it. - -Google Mock guarantees that the action for a mock function is done in -the same thread that called the mock function. For example, in - -``` - EXPECT_CALL(mock, Foo(1)) - .WillOnce(action1); - EXPECT_CALL(mock, Foo(2)) - .WillOnce(action2); -``` - -if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, -Google Mock will execute `action1` in thread 1 and `action2` in thread -2. - -Google Mock does _not_ impose a sequence on actions performed in -different threads (doing so may create deadlocks as the actions may -need to cooperate). This means that the execution of `action1` and -`action2` in the above example _may_ interleave. If this is a problem, -you should add proper synchronization logic to `action1` and `action2` -to make the test thread-safe. - - -Also, remember that `DefaultValue` is a global resource that -potentially affects _all_ living mock objects in your -program. Naturally, you won't want to mess with it from multiple -threads or when there still are mocks in action. - -## Controlling How Much Information Google Mock Prints ## - -When Google Mock sees something that has the potential of being an -error (e.g. a mock function with no expectation is called, a.k.a. an -uninteresting call, which is allowed but perhaps you forgot to -explicitly ban the call), it prints some warning messages, including -the arguments of the function and the return value. Hopefully this -will remind you to take a look and see if there is indeed a problem. - -Sometimes you are confident that your tests are correct and may not -appreciate such friendly messages. Some other times, you are debugging -your tests or learning about the behavior of the code you are testing, -and wish you could observe every mock call that happens (including -argument values and the return value). Clearly, one size doesn't fit -all. - -You can control how much Google Mock tells you using the -`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string -with three possible values: - - * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. - * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. - * `error`: Google Mock will print errors only (least verbose). - -Alternatively, you can adjust the value of that flag from within your -tests like so: - -``` - ::testing::FLAGS_gmock_verbose = "error"; -``` - -Now, judiciously use the right flag to enable Google Mock serve you better! - -## Gaining Super Vision into Mock Calls ## - -You have a test using Google Mock. It fails: Google Mock tells you -that some expectations aren't satisfied. However, you aren't sure why: -Is there a typo somewhere in the matchers? Did you mess up the order -of the `EXPECT_CALL`s? Or is the code under test doing something -wrong? How can you find out the cause? - -Won't it be nice if you have X-ray vision and can actually see the -trace of all `EXPECT_CALL`s and mock method calls as they are made? -For each call, would you like to see its actual argument values and -which `EXPECT_CALL` Google Mock thinks it matches? - -You can unlock this power by running your test with the -`--gmock_verbose=info` flag. For example, given the test program: - -``` -using testing::_; -using testing::HasSubstr; -using testing::Return; - -class MockFoo { - public: - MOCK_METHOD2(F, void(const string& x, const string& y)); -}; - -TEST(Foo, Bar) { - MockFoo mock; - EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); - EXPECT_CALL(mock, F("a", "b")); - EXPECT_CALL(mock, F("c", HasSubstr("d"))); - - mock.F("a", "good"); - mock.F("a", "b"); -} -``` - -if you run it with `--gmock_verbose=info`, you will see this output: - -``` -[ RUN ] Foo.Bar - -foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked -foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked -foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked -foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... - Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") -foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... - Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") -foo_test.cc:16: Failure -Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... - Expected: to be called once - Actual: never called - unsatisfied and active -[ FAILED ] Foo.Bar -``` - -Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo -and should actually be `"a"`. With the above message, you should see -that the actual `F("a", "good")` call is matched by the first -`EXPECT_CALL`, not the third as you thought. From that it should be -obvious that the third `EXPECT_CALL` is written wrong. Case solved. - -## Running Tests in Emacs ## - -If you build and run your tests in Emacs, the source file locations of -Google Mock and [Google Test](../../googletest/) -errors will be highlighted. Just press `` on one of them and -you'll be taken to the offending line. Or, you can just type `C-x `` -to jump to the next error. - -To make it even easier, you can add the following lines to your -`~/.emacs` file: - -``` -(global-set-key "\M-m" 'compile) ; m is for make -(global-set-key [M-down] 'next-error) -(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) -``` - -Then you can type `M-m` to start a build, or `M-up`/`M-down` to move -back and forth between errors. - -## Fusing Google Mock Source Files ## - -Google Mock's implementation consists of dozens of files (excluding -its own tests). Sometimes you may want them to be packaged up in -fewer files instead, such that you can easily copy them to a new -machine and start hacking there. For this we provide an experimental -Python script `fuse_gmock_files.py` in the `scripts/` directory -(starting with release 1.2.0). Assuming you have Python 2.4 or above -installed on your machine, just go to that directory and run -``` -python fuse_gmock_files.py OUTPUT_DIR -``` - -and you should see an `OUTPUT_DIR` directory being created with files -`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. -These three files contain everything you need to use Google Mock (and -Google Test). Just copy them to anywhere you want and you are ready -to write tests and use mocks. You can use the -[scrpts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests -against them. - -# Extending Google Mock # - -## Writing New Matchers Quickly ## - -The `MATCHER*` family of macros can be used to define custom matchers -easily. The syntax: - -``` -MATCHER(name, description_string_expression) { statements; } -``` - -will define a matcher with the given name that executes the -statements, which must return a `bool` to indicate if the match -succeeds. Inside the statements, you can refer to the value being -matched by `arg`, and refer to its type by `arg_type`. - -The description string is a `string`-typed expression that documents -what the matcher does, and is used to generate the failure message -when the match fails. It can (and should) reference the special -`bool` variable `negation`, and should evaluate to the description of -the matcher when `negation` is `false`, or that of the matcher's -negation when `negation` is `true`. - -For convenience, we allow the description string to be empty (`""`), -in which case Google Mock will use the sequence of words in the -matcher name as the description. - -For example: -``` -MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } -``` -allows you to write -``` - // Expects mock_foo.Bar(n) to be called where n is divisible by 7. - EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); -``` -or, -``` -using ::testing::Not; -... - EXPECT_THAT(some_expression, IsDivisibleBy7()); - EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); -``` -If the above assertions fail, they will print something like: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 -... - Value of: some_other_expression - Expected: not (is divisible by 7) - Actual: 21 -``` -where the descriptions `"is divisible by 7"` and `"not (is divisible -by 7)"` are automatically calculated from the matcher name -`IsDivisibleBy7`. - -As you may have noticed, the auto-generated descriptions (especially -those for the negation) may not be so great. You can always override -them with a string expression of your own: -``` -MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + - " divisible by 7") { - return (arg % 7) == 0; -} -``` - -Optionally, you can stream additional information to a hidden argument -named `result_listener` to explain the match result. For example, a -better definition of `IsDivisibleBy7` is: -``` -MATCHER(IsDivisibleBy7, "") { - if ((arg % 7) == 0) - return true; - - *result_listener << "the remainder is " << (arg % 7); - return false; -} -``` - -With this definition, the above assertion will give a better message: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 (the remainder is 6) -``` - -You should let `MatchAndExplain()` print _any additional information_ -that can help a user understand the match result. Note that it should -explain why the match succeeds in case of a success (unless it's -obvious) - this is useful when the matcher is used inside -`Not()`. There is no need to print the argument value itself, as -Google Mock already prints it for you. - -**Notes:** - - 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. - 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. - -## Writing New Parameterized Matchers Quickly ## - -Sometimes you'll want to define a matcher that has parameters. For that you -can use the macro: -``` -MATCHER_P(name, param_name, description_string) { statements; } -``` -where the description string can be either `""` or a string expression -that references `negation` and `param_name`. - -For example: -``` -MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -``` -will allow you to write: -``` - EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -``` -which may lead to this message (assuming `n` is 10): -``` - Value of: Blah("a") - Expected: has absolute value 10 - Actual: -9 -``` - -Note that both the matcher description and its parameter are -printed, making the message human-friendly. - -In the matcher definition body, you can write `foo_type` to -reference the type of a parameter named `foo`. For example, in the -body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write -`value_type` to refer to the type of `value`. - -Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to -`MATCHER_P10` to support multi-parameter matchers: -``` -MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } -``` - -Please note that the custom description string is for a particular -**instance** of the matcher, where the parameters have been bound to -actual values. Therefore usually you'll want the parameter values to -be part of the description. Google Mock lets you do that by -referencing the matcher parameters in the description string -expression. - -For example, -``` - using ::testing::PrintToString; - MATCHER_P2(InClosedRange, low, hi, - std::string(negation ? "isn't" : "is") + " in range [" + - PrintToString(low) + ", " + PrintToString(hi) + "]") { - return low <= arg && arg <= hi; - } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the message: -``` - Expected: is in range [4, 6] -``` - -If you specify `""` as the description, the failure message will -contain the sequence of words in the matcher name followed by the -parameter values printed as a tuple. For example, -``` - MATCHER_P2(InClosedRange, low, hi, "") { ... } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the text: -``` - Expected: in closed range (4, 6) -``` - -For the purpose of typing, you can view -``` -MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -``` -as shorthand for -``` -template -FooMatcherPk -Foo(p1_type p1, ..., pk_type pk) { ... } -``` - -When you write `Foo(v1, ..., vk)`, the compiler infers the types of -the parameters `v1`, ..., and `vk` for you. If you are not happy with -the result of the type inference, you can specify the types by -explicitly instantiating the template, as in `Foo(5, false)`. -As said earlier, you don't get to (or need to) specify -`arg_type` as that's determined by the context in which the matcher -is used. - -You can assign the result of expression `Foo(p1, ..., pk)` to a -variable of type `FooMatcherPk`. This can be -useful when composing matchers. Matchers that don't have a parameter -or have only one parameter have special types: you can assign `Foo()` -to a `FooMatcher`-typed variable, and assign `Foo(p)` to a -`FooMatcherP`-typed variable. - -While you can instantiate a matcher template with reference types, -passing the parameters by pointer usually makes your code more -readable. If, however, you still want to pass a parameter by -reference, be aware that in the failure message generated by the -matcher you will see the value of the referenced object but not its -address. - -You can overload matchers with different numbers of parameters: -``` -MATCHER_P(Blah, a, description_string_1) { ... } -MATCHER_P2(Blah, a, b, description_string_2) { ... } -``` - -While it's tempting to always use the `MATCHER*` macros when defining -a new matcher, you should also consider implementing -`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see -the recipes that follow), especially if you need to use the matcher a -lot. While these approaches require more work, they give you more -control on the types of the value being matched and the matcher -parameters, which in general leads to better compiler error messages -that pay off in the long run. They also allow overloading matchers -based on parameter types (as opposed to just based on the number of -parameters). - -## Writing New Monomorphic Matchers ## - -A matcher of argument type `T` implements -`::testing::MatcherInterface` and does two things: it tests whether a -value of type `T` matches the matcher, and can describe what kind of -values it matches. The latter ability is used for generating readable -error messages when expectations are violated. - -The interface looks like this: - -``` -class MatchResultListener { - public: - ... - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x); - - // Returns the underlying ostream. - ::std::ostream* stream(); -}; - -template -class MatcherInterface { - public: - virtual ~MatcherInterface(); - - // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Describes this matcher to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. - virtual void DescribeNegationTo(::std::ostream* os) const; -}; -``` - -If you need a custom matcher but `Truly()` is not a good option (for -example, you may not be happy with the way `Truly(predicate)` -describes itself, or you may want your matcher to be polymorphic as -`Eq(value)` is), you can define a matcher to do whatever you want in -two steps: first implement the matcher interface, and then define a -factory function to create a matcher instance. The second step is not -strictly needed but it makes the syntax of using the matcher nicer. - -For example, you can define a matcher to test whether an `int` is -divisible by 7 and then use it like this: -``` -using ::testing::MakeMatcher; -using ::testing::Matcher; -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { - return (n % 7) == 0; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is divisible by 7"; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "is not divisible by 7"; - } -}; - -inline Matcher DivisibleBy7() { - return MakeMatcher(new DivisibleBy7Matcher); -} -... - - EXPECT_CALL(foo, Bar(DivisibleBy7())); -``` - -You may improve the matcher message by streaming additional -information to the `listener` argument in `MatchAndExplain()`: - -``` -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, - MatchResultListener* listener) const { - const int remainder = n % 7; - if (remainder != 0) { - *listener << "the remainder is " << remainder; - } - return remainder == 0; - } - ... -}; -``` - -Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: -``` -Value of: x -Expected: is divisible by 7 - Actual: 23 (the remainder is 2) -``` - -## Writing New Polymorphic Matchers ## - -You've learned how to write your own matchers in the previous -recipe. Just one problem: a matcher created using `MakeMatcher()` only -works for one particular type of arguments. If you want a -_polymorphic_ matcher that works with arguments of several types (for -instance, `Eq(x)` can be used to match a `value` as long as `value` == -`x` compiles -- `value` and `x` don't have to share the same type), -you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit -involved. - -Fortunately, most of the time you can define a polymorphic matcher -easily with the help of `MakePolymorphicMatcher()`. Here's how you can -define `NotNull()` as an example: - -``` -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -using ::testing::NotNull; -using ::testing::PolymorphicMatcher; - -class NotNullMatcher { - public: - // To implement a polymorphic matcher, first define a COPYABLE class - // that has three members MatchAndExplain(), DescribeTo(), and - // DescribeNegationTo(), like the following. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, - MatchResultListener* /* listener */) const { - return p != NULL; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } -}; - -// To construct a polymorphic matcher, pass an instance of the class -// to MakePolymorphicMatcher(). Note the return type. -inline PolymorphicMatcher NotNull() { - return MakePolymorphicMatcher(NotNullMatcher()); -} -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -**Note:** Your polymorphic matcher class does **not** need to inherit from -`MatcherInterface` or any other class, and its methods do **not** need -to be virtual. - -Like in a monomorphic matcher, you may explain the match result by -streaming additional information to the `listener` argument in -`MatchAndExplain()`. - -## Writing New Cardinalities ## - -A cardinality is used in `Times()` to tell Google Mock how many times -you expect a call to occur. It doesn't have to be exact. For example, -you can say `AtLeast(5)` or `Between(2, 4)`. - -If the built-in set of cardinalities doesn't suit you, you are free to -define your own by implementing the following interface (in namespace -`testing`): - -``` -class CardinalityInterface { - public: - virtual ~CardinalityInterface(); - - // Returns true iff call_count calls will satisfy this cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; -}; -``` - -For example, to specify that a call must occur even number of times, -you can write - -``` -using ::testing::Cardinality; -using ::testing::CardinalityInterface; -using ::testing::MakeCardinality; - -class EvenNumberCardinality : public CardinalityInterface { - public: - virtual bool IsSatisfiedByCallCount(int call_count) const { - return (call_count % 2) == 0; - } - - virtual bool IsSaturatedByCallCount(int call_count) const { - return false; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "called even number of times"; - } -}; - -Cardinality EvenNumber() { - return MakeCardinality(new EvenNumberCardinality); -} -... - - EXPECT_CALL(foo, Bar(3)) - .Times(EvenNumber()); -``` - -## Writing New Actions Quickly ## - -If the built-in actions don't work for you, and you find it -inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` -family to quickly define a new action that can be used in your code as -if it's a built-in action. - -By writing -``` -ACTION(name) { statements; } -``` -in a namespace scope (i.e. not inside a class or function), you will -define an action with the given name that executes the statements. -The value returned by `statements` will be used as the return value of -the action. Inside the statements, you can refer to the K-th -(0-based) argument of the mock function as `argK`. For example: -``` -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -``` -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function -arguments. Rest assured that your code is type-safe though: -you'll get a compiler error if `*arg1` doesn't support the `++` -operator, or if the type of `++(*arg1)` isn't compatible with the mock -function's return type. - -Another example: -``` -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` -defines an action `Foo()` that invokes argument #2 (a function pointer) -with 5, calls function `Blah()`, sets the value pointed to by argument -#1 to 0, and returns argument #0. - -For more convenience and flexibility, you can also use the following -pre-defined symbols in the body of `ACTION`: - -| `argK_type` | The type of the K-th (0-based) argument of the mock function | -|:------------|:-------------------------------------------------------------| -| `args` | All arguments of the mock function as a tuple | -| `args_type` | The type of all arguments of the mock function as a tuple | -| `return_type` | The return type of the mock function | -| `function_type` | The type of the mock function | - -For example, when using an `ACTION` as a stub action for mock function: -``` -int DoSomething(bool flag, int* ptr); -``` -we have: -| **Pre-defined Symbol** | **Is Bound To** | -|:-----------------------|:----------------| -| `arg0` | the value of `flag` | -| `arg0_type` | the type `bool` | -| `arg1` | the value of `ptr` | -| `arg1_type` | the type `int*` | -| `args` | the tuple `(flag, ptr)` | -| `args_type` | the type `::testing::tuple` | -| `return_type` | the type `int` | -| `function_type` | the type `int(bool, int*)` | - -## Writing New Parameterized Actions Quickly ## - -Sometimes you'll want to parameterize an action you define. For that -we have another macro -``` -ACTION_P(name, param) { statements; } -``` - -For example, -``` -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -``` -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term _arguments_ for the values used to -invoke the mock function, and the term _parameters_ for the values -used to instantiate an action. - -Note that you don't need to provide the type of the parameter either. -Suppose the parameter is named `param`, you can also use the -Google-Mock-defined symbol `param_type` to refer to the type of the -parameter as inferred by the compiler. For example, in the body of -`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. - -Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support -multi-parameter actions. For example, -``` -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -``` -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the -number of parameters is 0. - -You can also easily define actions overloaded on the number of parameters: -``` -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -## Restricting the Type of an Argument or Parameter in an ACTION ## - -For maximum brevity and reusability, the `ACTION*` macros don't ask -you to provide the types of the mock function arguments and the action -parameters. Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. -There are several tricks to do that. For example: -``` -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` -where `StaticAssertTypeEq` is a compile-time assertion in Google Test -that verifies two types are the same. - -## Writing New Action Templates Quickly ## - -Sometimes you want to give an action explicit template parameters that -cannot be inferred from its value parameters. `ACTION_TEMPLATE()` -supports that and can be viewed as an extension to `ACTION()` and -`ACTION_P*()`. - -The syntax: -``` -ACTION_TEMPLATE(ActionName, - HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), - AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -``` - -defines an action template that takes _m_ explicit template parameters -and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is -between 0 and 10. `name_i` is the name of the i-th template -parameter, and `kind_i` specifies whether it's a `typename`, an -integral constant, or a template. `p_i` is the name of the i-th value -parameter. - -Example: -``` -// DuplicateArg(output) converts the k-th argument of the mock -// function to type T and copies it to *output. -ACTION_TEMPLATE(DuplicateArg, - // Note the comma between int and k: - HAS_2_TEMPLATE_PARAMS(int, k, typename, T), - AND_1_VALUE_PARAMS(output)) { - *output = T(::testing::get(args)); -} -``` - -To create an instance of an action template, write: -``` - ActionName(v1, ..., v_n) -``` -where the `t`s are the template arguments and the -`v`s are the value arguments. The value argument -types are inferred by the compiler. For example: -``` -using ::testing::_; -... - int n; - EXPECT_CALL(mock, Foo(_, _)) - .WillOnce(DuplicateArg<1, unsigned char>(&n)); -``` - -If you want to explicitly specify the value argument types, you can -provide additional template arguments: -``` - ActionName(v1, ..., v_n) -``` -where `u_i` is the desired type of `v_i`. - -`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the -number of value parameters, but not on the number of template -parameters. Without the restriction, the meaning of the following is -unclear: - -``` - OverloadedAction(x); -``` - -Are we using a single-template-parameter action where `bool` refers to -the type of `x`, or a two-template-parameter action where the compiler -is asked to infer the type of `x`? - -## Using the ACTION Object's Type ## - -If you are writing a function that returns an `ACTION` object, you'll -need to know its type. The type depends on the macro used to define -the action and the parameter types. The rule is relatively simple: -| **Given Definition** | **Expression** | **Has Type** | -|:---------------------|:---------------|:-------------| -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | -| ... | ... | ... | - -Note that we have to pick different suffixes (`Action`, `ActionP`, -`ActionP2`, and etc) for actions with different numbers of value -parameters, or the action definitions cannot be overloaded on the -number of them. - -## Writing New Monomorphic Actions ## - -While the `ACTION*` macros are very convenient, sometimes they are -inappropriate. For example, despite the tricks shown in the previous -recipes, they don't let you directly specify the types of the mock -function arguments and the action parameters, which in general leads -to unoptimized compiler error messages that can baffle unfamiliar -users. They also don't allow overloading actions based on parameter -types without jumping through some hoops. - -An alternative to the `ACTION*` macros is to implement -`::testing::ActionInterface`, where `F` is the type of the mock -function in which the action will be used. For example: - -``` -template class ActionInterface { - public: - virtual ~ActionInterface(); - - // Performs the action. Result is the return type of function type - // F, and ArgumentTuple is the tuple of arguments of F. - // - // For example, if F is int(bool, const string&), then Result would - // be int, and ArgumentTuple would be ::testing::tuple. - virtual Result Perform(const ArgumentTuple& args) = 0; -}; - -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::MakeAction; - -typedef int IncrementMethod(int*); - -class IncrementArgumentAction : public ActionInterface { - public: - virtual int Perform(const ::testing::tuple& args) { - int* p = ::testing::get<0>(args); // Grabs the first argument. - return *p++; - } -}; - -Action IncrementArgument() { - return MakeAction(new IncrementArgumentAction); -} -... - - EXPECT_CALL(foo, Baz(_)) - .WillOnce(IncrementArgument()); - - int n = 5; - foo.Baz(&n); // Should return 5 and change n to 6. -``` - -## Writing New Polymorphic Actions ## - -The previous recipe showed you how to define your own action. This is -all good, except that you need to know the type of the function in -which the action will be used. Sometimes that can be a problem. For -example, if you want to use the action in functions with _different_ -types (e.g. like `Return()` and `SetArgPointee()`). - -If an action can be used in several types of mock functions, we say -it's _polymorphic_. The `MakePolymorphicAction()` function template -makes it easy to define such an action: - -``` -namespace testing { - -template -PolymorphicAction MakePolymorphicAction(const Impl& impl); - -} // namespace testing -``` - -As an example, let's define an action that returns the second argument -in the mock function's argument list. The first step is to define an -implementation class: - -``` -class ReturnSecondArgumentAction { - public: - template - Result Perform(const ArgumentTuple& args) const { - // To get the i-th (0-based) argument, use ::testing::get(args). - return ::testing::get<1>(args); - } -}; -``` - -This implementation class does _not_ need to inherit from any -particular class. What matters is that it must have a `Perform()` -method template. This method template takes the mock function's -arguments as a tuple in a **single** argument, and returns the result of -the action. It can be either `const` or not, but must be invokable -with exactly one template argument, which is the result type. In other -words, you must be able to call `Perform(args)` where `R` is the -mock function's return type and `args` is its arguments in a tuple. - -Next, we use `MakePolymorphicAction()` to turn an instance of the -implementation class into the polymorphic action we need. It will be -convenient to have a wrapper for this: - -``` -using ::testing::MakePolymorphicAction; -using ::testing::PolymorphicAction; - -PolymorphicAction ReturnSecondArgument() { - return MakePolymorphicAction(ReturnSecondArgumentAction()); -} -``` - -Now, you can use this polymorphic action the same way you use the -built-in ones: - -``` -using ::testing::_; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, int(bool flag, int n)); - MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(ReturnSecondArgument()); - EXPECT_CALL(foo, DoThat(_, _, _)) - .WillOnce(ReturnSecondArgument()); - ... - foo.DoThis(true, 5); // Will return 5. - foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". -``` - -## Teaching Google Mock How to Print Your Values ## - -When an uninteresting or unexpected call occurs, Google Mock prints the -argument values and the stack trace to help you debug. Assertion -macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in -question when the assertion fails. Google Mock and Google Test do this using -Google Test's user-extensible value printer. - -This printer knows how to print built-in C++ types, native arrays, STL -containers, and any type that supports the `<<` operator. For other -types, it prints the raw bytes in the value and hopes that you the -user can figure it out. -[Google Test's advanced guide](../../googletest/docs/AdvancedGuide.md#teaching-google-test-how-to-print-your-values) -explains how to extend the printer to do a better job at -printing your particular type than to dump the bytes. diff --git a/src/libtoast/gtest/googlemock/docs/DesignDoc.md b/src/libtoast/gtest/googlemock/docs/DesignDoc.md deleted file mode 100644 index 3f515c3b6..000000000 --- a/src/libtoast/gtest/googlemock/docs/DesignDoc.md +++ /dev/null @@ -1,280 +0,0 @@ -This page discusses the design of new Google Mock features. - - - -# Macros for Defining Actions # - -## Problem ## - -Due to the lack of closures in C++, it currently requires some -non-trivial effort to define a custom action in Google Mock. For -example, suppose you want to "increment the value pointed to by the -second argument of the mock function and return it", you could write: - -``` -int IncrementArg1(Unused, int* p, Unused) { - return ++(*p); -} - -... WillOnce(Invoke(IncrementArg1)); -``` - -There are several things unsatisfactory about this approach: - - * Even though the action only cares about the second argument of the mock function, its definition needs to list other arguments as dummies. This is tedious. - * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction. - * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`. - -The latter two problems can be overcome using `MakePolymorphicAction()`, -but it requires much more boilerplate code: - -``` -class IncrementArg1Action { - public: - template - Result Perform(const ArgumentTuple& args) const { - return ++(*tr1::get<1>(args)); - } -}; - -PolymorphicAction IncrementArg1() { - return MakePolymorphicAction(IncrementArg1Action()); -} - -... WillOnce(IncrementArg1()); -``` - -Our goal is to allow defining custom actions with the least amount of -boiler-plate C++ requires. - -## Solution ## - -We propose to introduce a new macro: -``` -ACTION(name) { statements; } -``` - -Using this in a namespace scope will define an action with the given -name that executes the statements. Inside the statements, you can -refer to the K-th (0-based) argument of the mock function as `argK`. -For example: -``` -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -``` -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function -arguments, as brevity is a top design goal here. Rest assured that -your code is still type-safe though: you'll get a compiler error if -`*arg1` doesn't support the `++` operator, or if the type of -`++(*arg1)` isn't compatible with the mock function's return type. - -Another example: -``` -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` -defines an action `Foo()` that invokes argument #2 (a function pointer) -with 5, calls function `Blah()`, sets the value pointed to by argument -#1 to 0, and returns argument #0. - -For more convenience and flexibility, you can also use the following -pre-defined symbols in the body of `ACTION`: - -| `argK_type` | The type of the K-th (0-based) argument of the mock function | -|:------------|:-------------------------------------------------------------| -| `args` | All arguments of the mock function as a tuple | -| `args_type` | The type of all arguments of the mock function as a tuple | -| `return_type` | The return type of the mock function | -| `function_type` | The type of the mock function | - -For example, when using an `ACTION` as a stub action for mock function: -``` -int DoSomething(bool flag, int* ptr); -``` -we have: -| **Pre-defined Symbol** | **Is Bound To** | -|:-----------------------|:----------------| -| `arg0` | the value of `flag` | -| `arg0_type` | the type `bool` | -| `arg1` | the value of `ptr` | -| `arg1_type` | the type `int*` | -| `args` | the tuple `(flag, ptr)` | -| `args_type` | the type `std::tr1::tuple` | -| `return_type` | the type `int` | -| `function_type` | the type `int(bool, int*)` | - -## Parameterized actions ## - -Sometimes you'll want to parameterize the action. For that we propose -another macro -``` -ACTION_P(name, param) { statements; } -``` - -For example, -``` -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -``` -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term _arguments_ for the values used to -invoke the mock function, and the term _parameters_ for the values -used to instantiate an action. - -Note that you don't need to provide the type of the parameter either. -Suppose the parameter is named `param`, you can also use the -Google-Mock-defined symbol `param_type` to refer to the type of the -parameter as inferred by the compiler. - -We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support -multi-parameter actions. For example, -``` -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -``` -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the -number of parameters is 0. - -## Advanced Usages ## - -### Overloading Actions ### - -You can easily define actions overloaded on the number of parameters: -``` -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -### Restricting the Type of an Argument or Parameter ### - -For maximum brevity and reusability, the `ACTION*` macros don't let -you specify the types of the mock function arguments and the action -parameters. Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. -There are several tricks to do that. For example: -``` -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` -where `StaticAssertTypeEq` is a compile-time assertion we plan to add to -Google Test (the name is chosen to match `static_assert` in C++0x). - -### Using the ACTION Object's Type ### - -If you are writing a function that returns an `ACTION` object, you'll -need to know its type. The type depends on the macro used to define -the action and the parameter types. The rule is relatively simple: -| **Given Definition** | **Expression** | **Has Type** | -|:---------------------|:---------------|:-------------| -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| ... | ... | ... | - -Note that we have to pick different suffixes (`Action`, `ActionP`, -`ActionP2`, and etc) for actions with different numbers of parameters, -or the action definitions cannot be overloaded on the number of -parameters. - -## When to Use ## - -While the new macros are very convenient, please also consider other -means of implementing actions (e.g. via `ActionInterface` or -`MakePolymorphicAction()`), especially if you need to use the defined -action a lot. While the other approaches require more work, they give -you more control on the types of the mock function arguments and the -action parameters, which in general leads to better compiler error -messages that pay off in the long run. They also allow overloading -actions based on parameter types, as opposed to just the number of -parameters. - -## Related Work ## - -As you may have realized, the `ACTION*` macros resemble closures (also -known as lambda expressions or anonymous functions). Indeed, both of -them seek to lower the syntactic overhead for defining a function. - -C++0x will support lambdas, but they are not part of C++ right now. -Some non-standard libraries (most notably BLL or Boost Lambda Library) -try to alleviate this problem. However, they are not a good choice -for defining actions as: - - * They are non-standard and not widely installed. Google Mock only depends on standard libraries and `tr1::tuple`, which is part of the new C++ standard and comes with gcc 4+. We want to keep it that way. - * They are not trivial to learn. - * They will become obsolete when C++0x's lambda feature is widely supported. We don't want to make our users use a dying library. - * Since they are based on operators, they are rather ad hoc: you cannot use statements, and you cannot pass the lambda arguments to a function, for example. - * They have subtle semantics that easily confuses new users. For example, in expression `_1++ + foo++`, `foo` will be incremented only once where the expression is evaluated, while `_1` will be incremented every time the unnamed function is invoked. This is far from intuitive. - -`ACTION*` avoid all these problems. - -## Future Improvements ## - -There may be a need for composing `ACTION*` definitions (i.e. invoking -another `ACTION` inside the definition of one `ACTION*`). We are not -sure we want it yet, as one can get a similar effect by putting -`ACTION` definitions in function templates and composing the function -templates. We'll revisit this based on user feedback. - -The reason we don't allow `ACTION*()` inside a function body is that -the current C++ standard doesn't allow function-local types to be used -to instantiate templates. The upcoming C++0x standard will lift this -restriction. Once this feature is widely supported by compilers, we -can revisit the implementation and add support for using `ACTION*()` -inside a function. - -C++0x will also support lambda expressions. When they become -available, we may want to support using lambdas as actions. - -# Macros for Defining Matchers # - -Once the macros for defining actions are implemented, we plan to do -the same for matchers: - -``` -MATCHER(name) { statements; } -``` - -where you can refer to the value being matched as `arg`. For example, -given: - -``` -MATCHER(IsPositive) { return arg > 0; } -``` - -you can use `IsPositive()` as a matcher that matches a value iff it is -greater than 0. - -We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized -matchers. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/DevGuide.md b/src/libtoast/gtest/googlemock/docs/DevGuide.md deleted file mode 100644 index f4bab75ca..000000000 --- a/src/libtoast/gtest/googlemock/docs/DevGuide.md +++ /dev/null @@ -1,132 +0,0 @@ - - -If you are interested in understanding the internals of Google Mock, -building from source, or contributing ideas or modifications to the -project, then this document is for you. - -# Introduction # - -First, let's give you some background of the project. - -## Licensing ## - -All Google Mock source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php). - -## The Google Mock Community ## - -The Google Mock community exists primarily through the [discussion group](http://groups.google.com/group/googlemock), the -[issue tracker](https://github.com/google/googletest/issues) and, to a lesser extent, the [source control repository](../). You are definitely encouraged to contribute to the -discussion and you can also help us to keep the effectiveness of the -group high by following and promoting the guidelines listed here. - -### Please Be Friendly ### - -Showing courtesy and respect to others is a vital part of the Google -culture, and we strongly encourage everyone participating in Google -Mock development to join us in accepting nothing less. Of course, -being courteous is not the same as failing to constructively disagree -with each other, but it does mean that we should be respectful of each -other when enumerating the 42 technical reasons that a particular -proposal may not be the best choice. There's never a reason to be -antagonistic or dismissive toward anyone who is sincerely trying to -contribute to a discussion. - -Sure, C++ testing is serious business and all that, but it's also -a lot of fun. Let's keep it that way. Let's strive to be one of the -friendliest communities in all of open source. - -### Where to Discuss Google Mock ### - -As always, discuss Google Mock in the official [Google C++ Mocking Framework discussion group](http://groups.google.com/group/googlemock). You don't have to actually submit -code in order to sign up. Your participation itself is a valuable -contribution. - -# Working with the Code # - -If you want to get your hands dirty with the code inside Google Mock, -this is the section for you. - -## Checking Out the Source from Subversion ## - -Checking out the Google Mock source is most useful if you plan to -tweak it yourself. You check out the source for Google Mock using a -[Subversion](http://subversion.tigris.org/) client as you would for any -other project hosted on Google Code. Please see the instruction on -the [source code access page](../) for how to do it. - -## Compiling from Source ## - -Once you check out the code, you can find instructions on how to -compile it in the [README](../README.md) file. - -## Testing ## - -A mocking framework is of no good if itself is not thoroughly tested. -Tests should be written for any new code, and changes should be -verified to not break existing tests before they are submitted for -review. To perform the tests, follow the instructions in [README](http://code.google.com/p/googlemock/source/browse/trunk/README) and -verify that there are no failures. - -# Contributing Code # - -We are excited that Google Mock is now open source, and hope to get -great patches from the community. Before you fire up your favorite IDE -and begin hammering away at that new feature, though, please take the -time to read this section and understand the process. While it seems -rigorous, we want to keep a high standard of quality in the code -base. - -## Contributor License Agreements ## - -You must sign a Contributor License Agreement (CLA) before we can -accept any code. The CLA protects you and us. - - * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). - * If you work for a company that wants to allow you to contribute your work to Google Mock, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). - -Follow either of the two links above to access the appropriate CLA and -instructions for how to sign and return it. - -## Coding Style ## - -To keep the source consistent, readable, diffable and easy to merge, -we use a fairly rigid coding style, as defined by the [google-styleguide](https://github.com/google/styleguide) project. All patches will be expected -to conform to the style outlined [here](https://github.com/google/styleguide/blob/gh-pages/cppguide.xml). - -## Submitting Patches ## - -Please do submit code. Here's what you need to do: - - 1. Normally you should make your change against the SVN trunk instead of a branch or a tag, as the latter two are for release control and should be treated mostly as read-only. - 1. Decide which code you want to submit. A submission should be a set of changes that addresses one issue in the [Google Mock issue tracker](http://code.google.com/p/googlemock/issues/list). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one. - 1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches. - 1. Ensure that your code adheres to the [Google Mock source code style](#Coding_Style.md). - 1. Ensure that there are unit tests for your code. - 1. Sign a Contributor License Agreement. - 1. Create a patch file using `svn diff`. - 1. We use [Rietveld](http://codereview.appspot.com/) to do web-based code reviews. You can read about the tool [here](https://github.com/rietveld-codereview/rietveld/wiki). When you are ready, upload your patch via Rietveld and notify `googlemock@googlegroups.com` to review it. There are several ways to upload the patch. We recommend using the [upload\_gmock.py](../scripts/upload_gmock.py) script, which you can find in the `scripts/` folder in the SVN trunk. - -## Google Mock Committers ## - -The current members of the Google Mock engineering team are the only -committers at present. In the great tradition of eating one's own -dogfood, we will be requiring each new Google Mock engineering team -member to earn the right to become a committer by following the -procedures in this document, writing consistently great code, and -demonstrating repeatedly that he or she truly gets the zen of Google -Mock. - -# Release Process # - -We follow the typical release process for Subversion-based projects: - - 1. A release branch named `release-X.Y` is created. - 1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable. - 1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch. - 1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time). - 1. Go back to step 1 to create another release branch and so on. - - ---- - -This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/). diff --git a/src/libtoast/gtest/googlemock/docs/Documentation.md b/src/libtoast/gtest/googlemock/docs/Documentation.md deleted file mode 100644 index 444151ee9..000000000 --- a/src/libtoast/gtest/googlemock/docs/Documentation.md +++ /dev/null @@ -1,12 +0,0 @@ -This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** -- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** - - * [ForDummies](ForDummies.md) -- start here if you are new to Google Mock. - * [CheatSheet](CheatSheet.md) -- a quick reference. - * [CookBook](CookBook.md) -- recipes for doing various tasks using Google Mock. - * [FrequentlyAskedQuestions](FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. - -To contribute code to Google Mock, read: - - * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. - * [Pump Manual](../googletest/docs/PumpManual.md) -- how we generate some of Google Mock's source files. diff --git a/src/libtoast/gtest/googlemock/docs/ForDummies.md b/src/libtoast/gtest/googlemock/docs/ForDummies.md deleted file mode 100644 index 0da4cbe27..000000000 --- a/src/libtoast/gtest/googlemock/docs/ForDummies.md +++ /dev/null @@ -1,439 +0,0 @@ - - -(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](FrequentlyAskedQuestions.md#how-am-i-supposed-to-make-sense-of-these-horrible-template-errors).) - -# What Is Google C++ Mocking Framework? # -When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). - -**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: - - * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. - * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. - -If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. - -**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. - -Using Google Mock involves three basic steps: - - 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; - 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; - 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. - -# Why Google Mock? # -While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: - - * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. - * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. - * The knowledge you gained from using one mock doesn't transfer to the next. - -In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. - -Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: - - * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". - * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). - * Your tests are brittle as some resources they use are unreliable (e.g. the network). - * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. - * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. - * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. - -We encourage you to use Google Mock as: - - * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! - * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. - -# Getting Started # -Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. - -# A Case for Mock Turtles # -Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: - -``` -class Turtle { - ... - virtual ~Turtle() {} - virtual void PenUp() = 0; - virtual void PenDown() = 0; - virtual void Forward(int distance) = 0; - virtual void Turn(int degrees) = 0; - virtual void GoTo(int x, int y) = 0; - virtual int GetX() const = 0; - virtual int GetY() const = 0; -}; -``` - -(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) - -You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. - -Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. - -# Writing the Mock Class # -If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) - -## How to Define It ## -Using the `Turtle` interface as example, here are the simple steps you need to follow: - - 1. Derive a class `MockTurtle` from `Turtle`. - 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](CookBook.md#mocking-nonvirtual-methods), it's much more involved). Count how many arguments it has. - 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. - 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). - 1. Repeat until all virtual functions you want to mock are done. - -After the process, you should have something like: - -``` -#include "gmock/gmock.h" // Brings in Google Mock. -class MockTurtle : public Turtle { - public: - ... - MOCK_METHOD0(PenUp, void()); - MOCK_METHOD0(PenDown, void()); - MOCK_METHOD1(Forward, void(int distance)); - MOCK_METHOD1(Turn, void(int degrees)); - MOCK_METHOD2(GoTo, void(int x, int y)); - MOCK_CONST_METHOD0(GetX, int()); - MOCK_CONST_METHOD0(GetY, int()); -}; -``` - -You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. - -**Tip:** If even this is too much work for you, you'll find the -`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line -tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, -and it will print the definition of the mock class for you. Due to the -complexity of the C++ language, this script may not always work, but -it can be quite handy when it does. For more details, read the [user documentation](../scripts/generator/README). - -## Where to Put It ## -When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) - -So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. - -Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. - -# Using Mocks in Tests # -Once you have a mock class, using it is easy. The typical work flow is: - - 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). - 1. Create some mock objects. - 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). - 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. - 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. - -Here's an example: - -``` -#include "path/to/mock-turtle.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -using ::testing::AtLeast; // #1 - -TEST(PainterTest, CanDrawSomething) { - MockTurtle turtle; // #2 - EXPECT_CALL(turtle, PenDown()) // #3 - .Times(AtLeast(1)); - - Painter painter(&turtle); // #4 - - EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); -} // #5 - -int main(int argc, char** argv) { - // The following line must be executed to initialize Google Mock - // (and Google Test) before running the tests. - ::testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: - -``` -path/to/my_test.cc:119: Failure -Actual function call count doesn't match this expectation: -Actually: never called; -Expected: called at least once. -``` - -**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. - -**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. - -**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. - -This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. - -Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. - -## Using Google Mock with Any Testing Framework ## -If you want to use something other than Google Test (e.g. [CppUnit](http://sourceforge.net/projects/cppunit/) or -[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: -``` -int main(int argc, char** argv) { - // The following line causes Google Mock to throw an exception on failure, - // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = true; - ::testing::InitGoogleMock(&argc, argv); - ... whatever your testing framework requires ... -} -``` - -This approach has a catch: it makes Google Mock throw an exception -from a mock object's destructor sometimes. With some compilers, this -sometimes causes the test program to crash. You'll still be able to -notice that the test has failed, but it's not a graceful failure. - -A better solution is to use Google Test's -[event listener API](../../googletest/docs/AdvancedGuide.md#extending-google-test-by-handling-test-events) -to report a test failure to your testing framework properly. You'll need to -implement the `OnTestPartResult()` method of the event listener interface, but it -should be straightforward. - -If this turns out to be too much work, we suggest that you stick with -Google Test, which works with Google Mock seamlessly (in fact, it is -technically part of Google Mock.). If there is a reason that you -cannot use Google Test, please let us know. - -# Setting Expectations # -The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." - -## General Syntax ## -In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: - -``` -EXPECT_CALL(mock_object, method(matchers)) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) - -The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. - -This syntax is designed to make an expectation read like English. For example, you can probably guess that - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .Times(5) - .WillOnce(Return(100)) - .WillOnce(Return(150)) - .WillRepeatedly(Return(200)); -``` - -says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). - -**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. - -## Matchers: What Arguments Do We Expect? ## -When a mock function takes arguments, we must specify what arguments we are expecting; for example: - -``` -// Expects the turtle to move forward by 100 units. -EXPECT_CALL(turtle, Forward(100)); -``` - -Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": - -``` -using ::testing::_; -... -// Expects the turtle to move forward. -EXPECT_CALL(turtle, Forward(_)); -``` - -`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. - -A list of built-in matchers can be found in the [CheatSheet](CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: - -``` -using ::testing::Ge;... -EXPECT_CALL(turtle, Forward(Ge(100))); -``` - -This checks that the turtle will be told to go forward by at least 100 units. - -## Cardinalities: How Many Times Will It Be Called? ## -The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. - -An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. - -We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](CheatSheet.md). - -The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: - - * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. - * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. - * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. - -**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? - -## Actions: What Should It Do? ## -Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. - -First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). In addition, in C++ 11 and above, a mock function whose return type is default-constructible (i.e. has a default constructor) has a default action of returning a default-constructed value. If you don't say anything, this behavior will be used. - -Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillOnce(Return(300)); -``` - -This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillRepeatedly(Return(300)); -``` - -says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. - -Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). - -What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](CheatSheet.md#actions). - -**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: - -``` -int n = 100; -EXPECT_CALL(turtle, GetX()) -.Times(4) -.WillRepeatedly(Return(n++)); -``` - -Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](CookBook.md). - -Time for another quiz! What do you think the following means? - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) -.Times(4) -.WillOnce(Return(100)); -``` - -Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. - -## Using Multiple Expectations ## -So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. - -By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: - -``` -using ::testing::_;... -EXPECT_CALL(turtle, Forward(_)); // #1 -EXPECT_CALL(turtle, Forward(10)) // #2 - .Times(2); -``` - -If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. - -**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. - -## Ordered vs Unordered Calls ## -By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. - -Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: - -``` -using ::testing::InSequence;... -TEST(FooTest, DrawsLineSegment) { - ... - { - InSequence dummy; - - EXPECT_CALL(turtle, PenDown()); - EXPECT_CALL(turtle, Forward(100)); - EXPECT_CALL(turtle, PenUp()); - } - Foo(); -} -``` - -By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. - -In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. - -(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](CookBook#Expecting_Partially_Ordered_Calls.md).) - -## All Expectations Are Sticky (Unless Said Otherwise) ## -Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? - -After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): - -``` -using ::testing::_;... -EXPECT_CALL(turtle, GoTo(_, _)) // #1 - .Times(AnyNumber()); -EXPECT_CALL(turtle, GoTo(0, 0)) // #2 - .Times(2); -``` - -Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. - -This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). - -Simple? Let's see if you've really understood it: what does the following code say? - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)); -} -``` - -If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! - -One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); -} -``` - -And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: - -``` -using ::testing::InSequence; -using ::testing::Return; -... -{ - InSequence s; - - for (int i = 1; i <= n; i++) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); - } -} -``` - -By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). - -## Uninteresting Calls ## -A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. - -In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. - -# What Now? # -Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. - -Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. diff --git a/src/libtoast/gtest/googlemock/docs/FrequentlyAskedQuestions.md b/src/libtoast/gtest/googlemock/docs/FrequentlyAskedQuestions.md deleted file mode 100644 index 5eac83f4b..000000000 --- a/src/libtoast/gtest/googlemock/docs/FrequentlyAskedQuestions.md +++ /dev/null @@ -1,628 +0,0 @@ - - -Please send your questions to the -[googlemock](http://groups.google.com/group/googlemock) discussion -group. If you need help with compiler errors, make sure you have -tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. - -## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## - -In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](CookBook.md#mocking-nonvirtual-methods). - -## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## - -After version 1.4.0 of Google Mock was released, we had an idea on how -to make it easier to write matchers that can generate informative -messages efficiently. We experimented with this idea and liked what -we saw. Therefore we decided to implement it. - -Unfortunately, this means that if you have defined your own matchers -by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, -your definitions will no longer compile. Matchers defined using the -`MATCHER*` family of macros are not affected. - -Sorry for the hassle if your matchers are affected. We believe it's -in everyone's long-term interest to make this change sooner than -later. Fortunately, it's usually not hard to migrate an existing -matcher to the new API. Here's what you need to do: - -If you wrote your matcher like this: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` - -you'll need to change it to: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` -(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second -argument of type `MatchResultListener*`.) - -If you were also using `ExplainMatchResultTo()` to improve the matcher -message: -``` -// Old matcher definition that doesn't work with the lastest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - - virtual void ExplainMatchResultTo(MyType value, - ::std::ostream* os) const { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Foo property is " << value.GetFoo(); - } - ... -}; -``` - -you should move the logic of `ExplainMatchResultTo()` into -`MatchAndExplain()`, using the `MatchResultListener` argument where -the `::std::ostream` was used: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Foo property is " << value.GetFoo(); - return value.GetFoo() > 5; - } - ... -}; -``` - -If your matcher is defined using `MakePolymorphicMatcher()`: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you should rename the `Matches()` method to `MatchAndExplain()` and -add a `MatchResultListener*` argument (the same as what you need to do -for matchers defined by implementing `MatcherInterface`): -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -If your polymorphic matcher uses `ExplainMatchResultTo()` for better -failure messages: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -void ExplainMatchResultTo(const MyGreatMatcher& matcher, - MyType value, - ::std::ostream* os) { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Bar property is " << value.GetBar(); -} -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you'll need to move the logic inside `ExplainMatchResultTo()` to -`MatchAndExplain()`: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Bar property is " << value.GetBar(); - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -For more information, you can read these -[two](CookBook.md#writing-new-monomorphic-matchers) -[recipes](CookBook.md#writing-new-polymorphic-matchers) -from the cookbook. As always, you -are welcome to post questions on `googlemock@googlegroups.com` if you -need any help. - -## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## - -Google Mock works out of the box with Google Test. However, it's easy -to configure it to work with any testing framework of your choice. -[Here](ForDummies.md#using-google-mock-with-any-testing-framework) is how. - -## How am I supposed to make sense of these horrible template errors? ## - -If you are confused by the compiler errors gcc threw at you, -try consulting the _Google Mock Doctor_ tool first. What it does is to -scan stdin for gcc error messages, and spit out diagnoses on the -problems (we call them diseases) your code has. - -To "install", run command: -``` -alias gmd='/scripts/gmock_doctor.py' -``` - -To use it, do: -``` - 2>&1 | gmd -``` - -For example: -``` -make my_test 2>&1 | gmd -``` - -Or you can run `gmd` and copy-n-paste gcc's error messages to it. - -## Can I mock a variadic function? ## - -You cannot mock a variadic function (i.e. a function taking ellipsis -(`...`) arguments) directly in Google Mock. - -The problem is that in general, there is _no way_ for a mock object to -know how many arguments are passed to the variadic method, and what -the arguments' types are. Only the _author of the base class_ knows -the protocol, and we cannot look into his head. - -Therefore, to mock such a function, the _user_ must teach the mock -object how to figure out the number of arguments and their types. One -way to do it is to provide overloaded versions of the function. - -Ellipsis arguments are inherited from C and not really a C++ feature. -They are unsafe to use and don't work with arguments that have -constructors or destructors. Therefore we recommend to avoid them in -C++ as much as possible. - -## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## - -If you compile this using Microsoft Visual C++ 2005 SP1: -``` -class Foo { - ... - virtual void Bar(const int i) = 0; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Bar, void(const int i)); -}; -``` -You may get the following warning: -``` -warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier -``` - -This is a MSVC bug. The same code compiles fine with gcc ,for -example. If you use Visual C++ 2008 SP1, you would get the warning: -``` -warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers -``` - -In C++, if you _declare_ a function with a `const` parameter, the -`const` modifier is _ignored_. Therefore, the `Foo` base class above -is equivalent to: -``` -class Foo { - ... - virtual void Bar(int i) = 0; // int or const int? Makes no difference. -}; -``` - -In fact, you can _declare_ Bar() with an `int` parameter, and _define_ -it with a `const int` parameter. The compiler will still match them -up. - -Since making a parameter `const` is meaningless in the method -_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. -That should workaround the VC bug. - -Note that we are talking about the _top-level_ `const` modifier here. -If the function parameter is passed by pointer or reference, declaring -the _pointee_ or _referee_ as `const` is still meaningful. For -example, the following two declarations are _not_ equivalent: -``` -void Bar(int* p); // Neither p nor *p is const. -void Bar(const int* p); // p is not const, but *p is. -``` - -## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## - -We've noticed that when the `/clr` compiler flag is used, Visual C++ -uses 5~6 times as much memory when compiling a mock class. We suggest -to avoid `/clr` when compiling native C++ mocks. - -## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## - -You might want to run your test with -`--gmock_verbose=info`. This flag lets Google Mock print a trace -of every mock function call it receives. By studying the trace, -you'll gain insights on why the expectations you set are not met. - -## How can I assert that a function is NEVER called? ## - -``` -EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## - -When Google Mock detects a failure, it prints relevant information -(the mock function arguments, the state of relevant expectations, and -etc) to help the user debug. If another failure is detected, Google -Mock will do the same, including printing the state of relevant -expectations. - -Sometimes an expectation's state didn't change between two failures, -and you'll see the same description of the state twice. They are -however _not_ redundant, as they refer to _different points in time_. -The fact they are the same _is_ interesting information. - -## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## - -Does the class (hopefully a pure interface) you are mocking have a -virtual destructor? - -Whenever you derive from a base class, make sure its destructor is -virtual. Otherwise Bad Things will happen. Consider the following -code: - -``` -class Base { - public: - // Not virtual, but should be. - ~Base() { ... } - ... -}; - -class Derived : public Base { - public: - ... - private: - std::string value_; -}; - -... - Base* p = new Derived; - ... - delete p; // Surprise! ~Base() will be called, but ~Derived() will not - // - value_ is leaked. -``` - -By changing `~Base()` to virtual, `~Derived()` will be correctly -called when `delete p` is executed, and the heap checker -will be happy. - -## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## - -When people complain about this, often they are referring to code like: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. However, I have to write the expectations in the -// reverse order. This sucks big time!!! -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); -``` - -The problem is that they didn't pick the **best** way to express the test's -intent. - -By default, expectations don't have to be matched in _any_ particular -order. If you want them to match in a certain order, you need to be -explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's -easy to accidentally over-specify your tests, and we want to make it -harder to do so. - -There are two better ways to write the test spec. You could either -put the expectations in sequence: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. Using a sequence, we can write the expectations -// in their natural order. -{ - InSequence s; - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -} -``` - -or you can put the sequence of actions in the same expectation: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -``` - -Back to the original questions: why does Google Mock search the -expectations (and `ON_CALL`s) from back to front? Because this -allows a user to set up a mock's behavior for the common case early -(e.g. in the mock's constructor or the test fixture's set-up phase) -and customize it with more specific rules later. If Google Mock -searches from front to back, this very useful pattern won't be -possible. - -## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## - -When choosing between being neat and being safe, we lean toward the -latter. So the answer is that we think it's better to show the -warning. - -Often people write `ON_CALL`s in the mock object's -constructor or `SetUp()`, as the default behavior rarely changes from -test to test. Then in the test body they set the expectations, which -are often different for each test. Having an `ON_CALL` in the set-up -part of a test doesn't mean that the calls are expected. If there's -no `EXPECT_CALL` and the method is called, it's possibly an error. If -we quietly let the call go through without notifying the user, bugs -may creep in unnoticed. - -If, however, you are sure that the calls are OK, you can write - -``` -EXPECT_CALL(foo, Bar(_)) - .WillRepeatedly(...); -``` - -instead of - -``` -ON_CALL(foo, Bar(_)) - .WillByDefault(...); -``` - -This tells Google Mock that you do expect the calls and no warning should be -printed. - -Also, you can control the verbosity using the `--gmock_verbose` flag. -If you find the output too noisy when debugging, just choose a less -verbose level. - -## How can I delete the mock function's argument in an action? ## - -If you find yourself needing to perform some action that's not -supported by Google Mock directly, remember that you can define your own -actions using -[MakeAction()](CookBook.md#writing-new-actions) or -[MakePolymorphicAction()](CookBook.md#writing_new_polymorphic_actions), -or you can write a stub function and invoke it using -[Invoke()](CookBook.md#using-functions_methods_functors). - -## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## - -What?! I think it's beautiful. :-) - -While which syntax looks more natural is a subjective matter to some -extent, Google Mock's syntax was chosen for several practical advantages it -has. - -Try to mock a function that takes a map as an argument: -``` -virtual int GetSize(const map& m); -``` - -Using the proposed syntax, it would be: -``` -MOCK_METHOD1(GetSize, int, const map& m); -``` - -Guess what? You'll get a compiler error as the compiler thinks that -`const map& m` are **two**, not one, arguments. To work -around this you can use `typedef` to give the map type a name, but -that gets in the way of your work. Google Mock's syntax avoids this -problem as the function's argument types are protected inside a pair -of parentheses: -``` -// This compiles fine. -MOCK_METHOD1(GetSize, int(const map& m)); -``` - -You still need a `typedef` if the return type contains an unprotected -comma, but that's much rarer. - -Other advantages include: - 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. - 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. - 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! - -## My code calls a static/global function. Can I mock it? ## - -You can, but you need to make some changes. - -In general, if you find yourself needing to mock a static function, -it's a sign that your modules are too tightly coupled (and less -flexible, less reusable, less testable, etc). You are probably better -off defining a small interface and call the function through that -interface, which then can be easily mocked. It's a bit of work -initially, but usually pays for itself quickly. - -This Google Testing Blog -[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) -says it excellently. Check it out. - -## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## - -I know it's not a question, but you get an answer for free any way. :-) - -With Google Mock, you can create mocks in C++ easily. And people might be -tempted to use them everywhere. Sometimes they work great, and -sometimes you may find them, well, a pain to use. So, what's wrong in -the latter case? - -When you write a test without using mocks, you exercise the code and -assert that it returns the correct value or that the system is in an -expected state. This is sometimes called "state-based testing". - -Mocks are great for what some call "interaction-based" testing: -instead of checking the system state at the very end, mock objects -verify that they are invoked the right way and report an error as soon -as it arises, giving you a handle on the precise context in which the -error was triggered. This is often more effective and economical to -do than state-based testing. - -If you are doing state-based testing and using a test double just to -simulate the real object, you are probably better off using a fake. -Using a mock in this case causes pain, as it's not a strong point for -mocks to perform complex actions. If you experience this and think -that mocks suck, you are just not using the right tool for your -problem. Or, you might be trying to solve the wrong problem. :-) - -## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## - -By all means, NO! It's just an FYI. - -What it means is that you have a mock function, you haven't set any -expectations on it (by Google Mock's rule this means that you are not -interested in calls to this function and therefore it can be called -any number of times), and it is called. That's OK - you didn't say -it's not OK to call the function! - -What if you actually meant to disallow this function to be called, but -forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While -one can argue that it's the user's fault, Google Mock tries to be nice and -prints you a note. - -So, when you see the message and believe that there shouldn't be any -uninteresting calls, you should investigate what's going on. To make -your life easier, Google Mock prints the function name and arguments -when an uninteresting call is encountered. - -## I want to define a custom action. Should I use Invoke() or implement the action interface? ## - -Either way is fine - you want to choose the one that's more convenient -for your circumstance. - -Usually, if your action is for a particular function type, defining it -using `Invoke()` should be easier; if your action can be used in -functions of different types (e.g. if you are defining -`Return(value)`), `MakePolymorphicAction()` is -easiest. Sometimes you want precise control on what types of -functions the action can be used in, and implementing -`ActionInterface` is the way to go here. See the implementation of -`Return()` in `include/gmock/gmock-actions.h` for an example. - -## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## - -You got this error as Google Mock has no idea what value it should return -when the mock method is called. `SetArgPointee()` says what the -side effect is, but doesn't say what the return value should be. You -need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. - -See this [recipe](CookBook.md#mocking_side_effects) for more details and an example. - - -## My question is not in your FAQ! ## - -If you cannot find the answer to your question in this FAQ, there are -some other resources you can use: - - 1. read other [documentation](Documentation.md), - 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), - 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). - -Please note that creating an issue in the -[issue tracker](https://github.com/google/googletest/issues) is _not_ -a good way to get your answer, as it is monitored infrequently by a -very small number of people. - -When asking a question, it's helpful to provide as much of the -following information as possible (people cannot help you if there's -not enough information in your question): - - * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), - * your operating system, - * the name and version of your compiler, - * the complete command line flags you give to your compiler, - * the complete compiler error messages (if the question is about compilation), - * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. diff --git a/src/libtoast/gtest/googlemock/docs/KnownIssues.md b/src/libtoast/gtest/googlemock/docs/KnownIssues.md deleted file mode 100644 index adadf5144..000000000 --- a/src/libtoast/gtest/googlemock/docs/KnownIssues.md +++ /dev/null @@ -1,19 +0,0 @@ -As any non-trivial software system, Google Mock has some known limitations and problems. We are working on improving it, and welcome your help! The follow is a list of issues we know about. - - - -## README contains outdated information on Google Mock's compatibility with other testing frameworks ## - -The `README` file in release 1.1.0 still says that Google Mock only works with Google Test. Actually, you can configure Google Mock to work with any testing framework you choose. - -## Tests failing on machines using Power PC CPUs (e.g. some Macs) ## - -`gmock_output_test` and `gmock-printers_test` are known to fail with Power PC CPUs. This is due to portability issues with these tests, and is not an indication of problems in Google Mock itself. You can safely ignore them. - -## Failed to resolve libgtest.so.0 in tests when built against installed Google Test ## - -This only applies if you manually built and installed Google Test, and then built a Google Mock against it (either explicitly, or because gtest-config was in your path post-install). In this situation, Libtool has a known issue with certain systems' ldconfig setup: - -http://article.gmane.org/gmane.comp.sysutils.automake.general/9025 - -This requires a manual run of "sudo ldconfig" after the "sudo make install" for Google Test before any binaries which link against it can be executed. This isn't a bug in our install, but we should at least have documented it or hacked a work-around into our install. We should have one of these solutions in our next release. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/README.md b/src/libtoast/gtest/googlemock/docs/README.md new file mode 100644 index 000000000..1bc57b799 --- /dev/null +++ b/src/libtoast/gtest/googlemock/docs/README.md @@ -0,0 +1,4 @@ +# Content Moved + +We are working on updates to the GoogleTest documentation, which has moved to +the top-level [docs](../../docs) directory. diff --git a/src/libtoast/gtest/googlemock/docs/v1_5/CheatSheet.md b/src/libtoast/gtest/googlemock/docs/v1_5/CheatSheet.md deleted file mode 100644 index 3c7bed4c6..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_5/CheatSheet.md +++ /dev/null @@ -1,525 +0,0 @@ - - -# Defining a Mock Class # - -## Mocking a Normal Class ## - -Given -``` -class Foo { - ... - virtual ~Foo(); - virtual int GetSize() const = 0; - virtual string Describe(const char* name) = 0; - virtual string Describe(int type) = 0; - virtual bool Process(Bar elem, int count) = 0; -}; -``` -(note that `~Foo()` **must** be virtual) we can define its mock as -``` -#include - -class MockFoo : public Foo { - MOCK_CONST_METHOD0(GetSize, int()); - MOCK_METHOD1(Describe, string(const char* name)); - MOCK_METHOD1(Describe, string(int type)); - MOCK_METHOD2(Process, bool(Bar elem, int count)); -}; -``` - -To create a "nice" mock object which ignores all uninteresting calls, -or a "strict" mock object, which treats them as failures: -``` -NiceMock nice_foo; // The type is a subclass of MockFoo. -StrictMock strict_foo; // The type is a subclass of MockFoo. -``` - -## Mocking a Class Template ## - -To mock -``` -template -class StackInterface { - public: - ... - virtual ~StackInterface(); - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; -``` -(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: -``` -template -class MockStack : public StackInterface { - public: - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Specifying Calling Conventions for Mock Functions ## - -If your mock function doesn't use the default calling convention, you -can specify it by appending `_WITH_CALLTYPE` to any of the macros -described in the previous two sections and supplying the calling -convention as the first argument to the macro. For example, -``` - MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); - MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); -``` -where `STDMETHODCALLTYPE` is defined by `` on Windows. - -# Using Mocks in Tests # - -The typical flow is: - 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. - 1. Create the mock objects. - 1. Optionally, set the default actions of the mock objects. - 1. Set your expectations on the mock objects (How will they be called? What wil they do?). - 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. - 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. - -Here is an example: -``` -using ::testing::Return; // #1 - -TEST(BarTest, DoesThis) { - MockFoo foo; // #2 - - ON_CALL(foo, GetSize()) // #3 - .WillByDefault(Return(1)); - // ... other default actions ... - - EXPECT_CALL(foo, Describe(5)) // #4 - .Times(3) - .WillRepeatedly(Return("Category 5")); - // ... other expectations ... - - EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 -} // #6 -``` - -# Setting Default Actions # - -Google Mock has a **built-in default action** for any function that -returns `void`, `bool`, a numeric value, or a pointer. - -To customize the default action for functions with return type `T` globally: -``` -using ::testing::DefaultValue; - -DefaultValue::Set(value); // Sets the default value to be returned. -// ... use the mocks ... -DefaultValue::Clear(); // Resets the default value. -``` - -To customize the default action for a particular method, use `ON_CALL()`: -``` -ON_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .WillByDefault(action); -``` - -# Setting Expectations # - -`EXPECT_CALL()` sets **expectations** on a mock method (How will it be -called? What will it do?): -``` -EXPECT_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .Times(cardinality) ? - .InSequence(sequences) * - .After(expectations) * - .WillOnce(action) * - .WillRepeatedly(action) ? - .RetiresOnSaturation(); ? -``` - -If `Times()` is omitted, the cardinality is assumed to be: - - * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; - * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or - * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. - -A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. - -# Matchers # - -A **matcher** matches a _single_ argument. You can use it inside -`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value -directly: - -| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | -|:------------------------------|:----------------------------------------| -| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | - -Built-in matchers (where `argument` is the function argument) are -divided into several categories: - -## Wildcard ## -|`_`|`argument` can be any value of the correct type.| -|:--|:-----------------------------------------------| -|`A()` or `An()`|`argument` can be any value of type `type`. | - -## Generic Comparison ## - -|`Eq(value)` or `value`|`argument == value`| -|:---------------------|:------------------| -|`Ge(value)` |`argument >= value`| -|`Gt(value)` |`argument > value` | -|`Le(value)` |`argument <= value`| -|`Lt(value)` |`argument < value` | -|`Ne(value)` |`argument != value`| -|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| -|`NotNull()` |`argument` is a non-null pointer (raw or smart).| -|`Ref(variable)` |`argument` is a reference to `variable`.| -|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| - -Except `Ref()`, these matchers make a _copy_ of `value` in case it's -modified or destructed later. If the compiler complains that `value` -doesn't have a public copy constructor, try wrap it in `ByRef()`, -e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure -`non_copyable_value` is not changed afterwards, or the meaning of your -matcher will be changed. - -## Floating-Point Matchers ## - -|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| -|:-------------------|:----------------------------------------------------------------------------------------------| -|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | -|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | -|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | - -The above matchers use ULP-based comparison (the same as used in -[Google Test](http://code.google.com/p/googletest/)). They -automatically pick a reasonable error bound based on the absolute -value of the expected value. `DoubleEq()` and `FloatEq()` conform to -the IEEE standard, which requires comparing two NaNs for equality to -return false. The `NanSensitive*` version instead treats two NaNs as -equal, which is often what a user wants. - -## String Matchers ## - -The `argument` can be either a C string or a C++ string object: - -|`ContainsRegex(string)`|`argument` matches the given regular expression.| -|:----------------------|:-----------------------------------------------| -|`EndsWith(suffix)` |`argument` ends with string `suffix`. | -|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | -|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| -|`StartsWith(prefix)` |`argument` starts with string `prefix`. | -|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | -|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| -|`StrEq(string)` |`argument` is equal to `string`. | -|`StrNe(string)` |`argument` is not equal to `string`. | - -`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide -strings as well. - -## Container Matchers ## - -Most STL-style containers support `==`, so you can use -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. If you want to write the elements in-line, -match them more flexibly, or get more informative messages, you can use: - -| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | -|:--------------|:-------------------------------------------------------------------------------------------| -|`ElementsAre(e0, e1, ..., en)`|`argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed.| -|`ElementsAreArray(array)` or `ElementsAreArray(array, count)`|The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array.| -| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | - -These matchers can also match: - - 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and - 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). - -where the array may be multi-dimensional (i.e. its elements can be arrays). - -## Member Matchers ## - -|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| -|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| -|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| -|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | -|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| - -## Matching the Result of a Function or Functor ## - -|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| -|:---------------|:---------------------------------------------------------------------| - -## Pointer Matchers ## - -|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| -|:-----------|:-----------------------------------------------------------------------------------------------| - -## Multiargument Matchers ## - -These are matchers on tuple types. They can be used in -`.With()`. The following can be used on functions with two
-arguments
`x` and `y`: - -|`Eq()`|`x == y`| -|:-----|:-------| -|`Ge()`|`x >= y`| -|`Gt()`|`x > y` | -|`Le()`|`x <= y`| -|`Lt()`|`x < y` | -|`Ne()`|`x != y`| - -You can use the following selectors to pick a subset of the arguments -(or reorder them) to participate in the matching: - -|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| -|:-----------|:-------------------------------------------------------------------| -|`Args(m)`|The `k` selected (using 0-based indices) arguments match `m`, e.g. `Args<1, 2>(Contains(5))`.| - -## Composite Matchers ## - -You can make a matcher from one or more other matchers: - -|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| -|:-----------------------|:---------------------------------------------------| -|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| -|`Not(m)` |`argument` doesn't match matcher `m`. | - -## Adapters for Matchers ## - -|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| -|:------------------|:--------------------------------------| -|`SafeMatcherCast(m)`| [safely casts](V1_5_CookBook#Casting_Matchers.md) matcher `m` to type `Matcher`. | -|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| - -## Matchers as Predicates ## - -|`Matches(m)`|a unary functor that returns `true` if the argument matches `m`.| -|:-----------|:---------------------------------------------------------------| -|`ExplainMatchResult(m, value, result_listener)`|returns `true` if `value` matches `m`, explaining the result to `result_listener`.| -|`Value(x, m)`|returns `true` if the value of `x` matches `m`. | - -## Defining Matchers ## - -| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | -|:-------------------------------------------------|:------------------------------------------------------| -| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, "is between %(a)s and %(b)s") { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | - -**Notes:** - - 1. The `MATCHER*` macros cannot be used inside a function or class. - 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). - 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. - -## Matchers as Test Assertions ## - -|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Assertions) if the value of `expression` doesn't match matcher `m`.| -|:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------| -|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | - -# Actions # - -**Actions** specify what a mock function should do when invoked. - -## Returning a Value ## - -|`Return()`|Return from a `void` mock function.| -|:---------|:----------------------------------| -|`Return(value)`|Return `value`. | -|`ReturnArg()`|Return the `N`-th (0-based) argument.| -|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| -|`ReturnNull()`|Return a null pointer. | -|`ReturnRef(variable)`|Return a reference to `variable`. | - -## Side Effects ## - -|`Assign(&variable, value)`|Assign `value` to variable.| -|:-------------------------|:--------------------------| -| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | -| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | -|`SetArgumentPointee(value)`|Assign `value` to the variable pointed by the `N`-th (0-based) argument.| -|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| -|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| -|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| - -## Using a Function or a Functor as an Action ## - -|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| -|:----------|:-----------------------------------------------------------------------------------------------------------------| -|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | -|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | -|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | -|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| - -The return value of the invoked function is used as the return value -of the action. - -When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: -``` - double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } - ... - EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); -``` - -In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, -``` - InvokeArgument<2>(5, string("Hi"), ByRef(foo)) -``` -calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. - -## Default Action ## - -|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| -|:------------|:--------------------------------------------------------------------| - -**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. - -## Composite Actions ## - -|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | -|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| -|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | -|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | -|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | -|`WithoutArgs(a)` |Perform action `a` without any arguments. | - -## Defining Actions ## - -| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | -|:--------------------------------------|:---------------------------------------------------------------------------------------| -| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | -| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | - -The `ACTION*` macros cannot be used inside a function or class. - -# Cardinalities # - -These are used in `Times()` to specify how many times a mock function will be called: - -|`AnyNumber()`|The function can be called any number of times.| -|:------------|:----------------------------------------------| -|`AtLeast(n)` |The call is expected at least `n` times. | -|`AtMost(n)` |The call is expected at most `n` times. | -|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| -|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| - -# Expectation Order # - -By default, the expectations can be matched in _any_ order. If some -or all expectations must be matched in a given order, there are two -ways to specify it. They can be used either independently or -together. - -## The After Clause ## - -``` -using ::testing::Expectation; -... -Expectation init_x = EXPECT_CALL(foo, InitX()); -Expectation init_y = EXPECT_CALL(foo, InitY()); -EXPECT_CALL(foo, Bar()) - .After(init_x, init_y); -``` -says that `Bar()` can be called only after both `InitX()` and -`InitY()` have been called. - -If you don't know how many pre-requisites an expectation has when you -write it, you can use an `ExpectationSet` to collect them: - -``` -using ::testing::ExpectationSet; -... -ExpectationSet all_inits; -for (int i = 0; i < element_count; i++) { - all_inits += EXPECT_CALL(foo, InitElement(i)); -} -EXPECT_CALL(foo, Bar()) - .After(all_inits); -``` -says that `Bar()` can be called only after all elements have been -initialized (but we don't care about which elements get initialized -before the others). - -Modifying an `ExpectationSet` after using it in an `.After()` doesn't -affect the meaning of the `.After()`. - -## Sequences ## - -When you have a long chain of sequential expectations, it's easier to -specify the order using **sequences**, which don't require you to given -each expectation in the chain a different name. All expected
-calls
in the same sequence must occur in the order they are -specified. - -``` -using ::testing::Sequence; -Sequence s1, s2; -... -EXPECT_CALL(foo, Reset()) - .InSequence(s1, s2) - .WillOnce(Return(true)); -EXPECT_CALL(foo, GetSize()) - .InSequence(s1) - .WillOnce(Return(1)); -EXPECT_CALL(foo, Describe(A())) - .InSequence(s2) - .WillOnce(Return("dummy")); -``` -says that `Reset()` must be called before _both_ `GetSize()` _and_ -`Describe()`, and the latter two can occur in any order. - -To put many expectations in a sequence conveniently: -``` -using ::testing::InSequence; -{ - InSequence dummy; - - EXPECT_CALL(...)...; - EXPECT_CALL(...)...; - ... - EXPECT_CALL(...)...; -} -``` -says that all expected calls in the scope of `dummy` must occur in -strict order. The name `dummy` is irrelevant.) - -# Verifying and Resetting a Mock # - -Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: -``` -using ::testing::Mock; -... -// Verifies and removes the expectations on mock_obj; -// returns true iff successful. -Mock::VerifyAndClearExpectations(&mock_obj); -... -// Verifies and removes the expectations on mock_obj; -// also removes the default actions set by ON_CALL(); -// returns true iff successful. -Mock::VerifyAndClear(&mock_obj); -``` - -You can also tell Google Mock that a mock object can be leaked and doesn't -need to be verified: -``` -Mock::AllowLeak(&mock_obj); -``` - -# Mock Classes # - -Google Mock defines a convenient mock class template -``` -class MockFunction { - public: - MOCK_METHODn(Call, R(A1, ..., An)); -}; -``` -See this [recipe](V1_5_CookBook#Using_Check_Points.md) for one application of it. - -# Flags # - -| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | -|:-------------------------------|:----------------------------------------------| -| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_5/CookBook.md b/src/libtoast/gtest/googlemock/docs/v1_5/CookBook.md deleted file mode 100644 index 26e153c6b..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_5/CookBook.md +++ /dev/null @@ -1,3250 +0,0 @@ - - -You can find recipes for using Google Mock here. If you haven't yet, -please read the [ForDummies](V1_5_ForDummies.md) document first to make sure you understand -the basics. - -**Note:** Google Mock lives in the `testing` name space. For -readability, it is recommended to write `using ::testing::Foo;` once in -your file before using the name `Foo` defined by Google Mock. We omit -such `using` statements in this page for brevity, but you should do it -in your own code. - -# Creating Mock Classes # - -## Mocking Private or Protected Methods ## - -You must always put a mock method definition (`MOCK_METHOD*`) in a -`public:` section of the mock class, regardless of the method being -mocked being `public`, `protected`, or `private` in the base class. -This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function -from outside of the mock class. (Yes, C++ allows a subclass to change -the access level of a virtual function in the base class.) Example: - -``` -class Foo { - public: - ... - virtual bool Transform(Gadget* g) = 0; - - protected: - virtual void Resume(); - - private: - virtual int GetTimeOut(); -}; - -class MockFoo : public Foo { - public: - ... - MOCK_METHOD1(Transform, bool(Gadget* g)); - - // The following must be in the public section, even though the - // methods are protected or private in the base class. - MOCK_METHOD0(Resume, void()); - MOCK_METHOD0(GetTimeOut, int()); -}; -``` - -## Mocking Overloaded Methods ## - -You can mock overloaded functions as usual. No special attention is required: - -``` -class Foo { - ... - - // Must be virtual as we'll inherit from Foo. - virtual ~Foo(); - - // Overloaded on the types and/or numbers of arguments. - virtual int Add(Element x); - virtual int Add(int times, Element x); - - // Overloaded on the const-ness of this object. - virtual Bar& GetBar(); - virtual const Bar& GetBar() const; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Add, int(Element x)); - MOCK_METHOD2(Add, int(int times, Element x); - - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -``` - -**Note:** if you don't mock all versions of the overloaded method, the -compiler will give you a warning about some methods in the base class -being hidden. To fix that, use `using` to bring them in scope: - -``` -class MockFoo : public Foo { - ... - using Foo::Add; - MOCK_METHOD1(Add, int(Element x)); - // We don't want to mock int Add(int times, Element x); - ... -}; -``` - -## Mocking Class Templates ## - -To mock a class template, append `_T` to the `MOCK_*` macros: - -``` -template -class StackInterface { - ... - // Must be virtual as we'll inherit from StackInterface. - virtual ~StackInterface(); - - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; - -template -class MockStack : public StackInterface { - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Mocking Nonvirtual Methods ## - -Google Mock can mock non-virtual functions to be used in what we call _hi-perf -dependency injection_. - -In this case, instead of sharing a common base class with the real -class, your mock class will be _unrelated_ to the real class, but -contain methods with the same signatures. The syntax for mocking -non-virtual methods is the _same_ as mocking virtual methods: - -``` -// A simple packet stream class. None of its members is virtual. -class ConcretePacketStream { - public: - void AppendPacket(Packet* new_packet); - const Packet* GetPacket(size_t packet_number) const; - size_t NumberOfPackets() const; - ... -}; - -// A mock packet stream class. It inherits from no other, but defines -// GetPacket() and NumberOfPackets(). -class MockPacketStream { - public: - MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); - MOCK_CONST_METHOD0(NumberOfPackets, size_t()); - ... -}; -``` - -Note that the mock class doesn't define `AppendPacket()`, unlike the -real class. That's fine as long as the test doesn't need to call it. - -Next, you need a way to say that you want to use -`ConcretePacketStream` in production code, and use `MockPacketStream` -in tests. Since the functions are not virtual and the two classes are -unrelated, you must specify your choice at _compile time_ (as opposed -to run time). - -One way to do it is to templatize your code that needs to use a packet -stream. More specifically, you will give your code a template type -argument for the type of the packet stream. In production, you will -instantiate your template with `ConcretePacketStream` as the type -argument. In tests, you will instantiate the same template with -`MockPacketStream`. For example, you may write: - -``` -template -void CreateConnection(PacketStream* stream) { ... } - -template -class PacketReader { - public: - void ReadPackets(PacketStream* stream, size_t packet_num); -}; -``` - -Then you can use `CreateConnection()` and -`PacketReader` in production code, and use -`CreateConnection()` and -`PacketReader` in tests. - -``` - MockPacketStream mock_stream; - EXPECT_CALL(mock_stream, ...)...; - .. set more expectations on mock_stream ... - PacketReader reader(&mock_stream); - ... exercise reader ... -``` - -## Mocking Free Functions ## - -It's possible to use Google Mock to mock a free function (i.e. a -C-style function or a static method). You just need to rewrite your -code to use an interface (abstract class). - -Instead of calling a free function (say, `OpenFile`) directly, -introduce an interface for it and have a concrete subclass that calls -the free function: - -``` -class FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) = 0; -}; - -class File : public FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) { - return OpenFile(path, mode); - } -}; -``` - -Your code should talk to `FileInterface` to open a file. Now it's -easy to mock out the function. - -This may seem much hassle, but in practice you often have multiple -related functions that you can put in the same interface, so the -per-function syntactic overhead will be much lower. - -If you are concerned about the performance overhead incurred by -virtual functions, and profiling confirms your concern, you can -combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). - -## Nice Mocks and Strict Mocks ## - -If a mock method has no `EXPECT_CALL` spec but is called, Google Mock -will print a warning about the "uninteresting call". The rationale is: - - * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. - * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. - -However, sometimes you may want to suppress all "uninteresting call" -warnings, while sometimes you may want the opposite, i.e. to treat all -of them as errors. Google Mock lets you make the decision on a -per-mock-object basis. - -Suppose your test uses a mock class `MockFoo`: - -``` -TEST(...) { - MockFoo mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -If a method of `mock_foo` other than `DoThis()` is called, it will be -reported by Google Mock as a warning. However, if you rewrite your -test to use `NiceMock` instead, the warning will be gone, -resulting in a cleaner test output: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -`NiceMock` is a subclass of `MockFoo`, so it can be used -wherever `MockFoo` is accepted. - -It also works if `MockFoo`'s constructor takes some arguments, as -`NiceMock` "inherits" `MockFoo`'s constructors: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -The usage of `StrictMock` is similar, except that it makes all -uninteresting calls failures: - -``` -using ::testing::StrictMock; - -TEST(...) { - StrictMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... - - // The test will fail if a method of mock_foo other than DoThis() - // is called. -} -``` - -There are some caveats though (I don't like them just as much as the -next guy, but sadly they are side effects of C++'s limitations): - - 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. - 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). - 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) - -Finally, you should be **very cautious** when using this feature, as the -decision you make applies to **all** future changes to the mock -class. If an important change is made in the interface you are mocking -(and thus in the mock class), it could break your tests (if you use -`StrictMock`) or let bugs pass through without a warning (if you use -`NiceMock`). Therefore, try to specify the mock's behavior using -explicit `EXPECT_CALL` first, and only turn to `NiceMock` or -`StrictMock` as the last resort. - -## Simplifying the Interface without Breaking Existing Code ## - -Sometimes a method has a long list of arguments that is mostly -uninteresting. For example, - -``` -class LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, - const char* message, size_t message_len) = 0; -}; -``` - -This method's argument list is lengthy and hard to work with (let's -say that the `message` argument is not even 0-terminated). If we mock -it as is, using the mock will be awkward. If, however, we try to -simplify this interface, we'll need to fix all clients depending on -it, which is often infeasible. - -The trick is to re-dispatch the method in the mock class: - -``` -class ScopedMockLog : public LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const tm* tm_time, - const char* message, size_t message_len) { - // We are only interested in the log severity, full file name, and - // log message. - Log(severity, full_filename, std::string(message, message_len)); - } - - // Implements the mock method: - // - // void Log(LogSeverity severity, - // const string& file_path, - // const string& message); - MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, - const string& message)); -}; -``` - -By defining a new mock method with a trimmed argument list, we make -the mock class much more user-friendly. - -## Alternative to Mocking Concrete Classes ## - -Often you may find yourself using classes that don't implement -interfaces. In order to test your code that uses such a class (let's -call it `Concrete`), you may be tempted to make the methods of -`Concrete` virtual and then mock it. - -Try not to do that. - -Making a non-virtual function virtual is a big decision. It creates an -extension point where subclasses can tweak your class' behavior. This -weakens your control on the class because now it's harder to maintain -the class' invariants. You should make a function virtual only when -there is a valid reason for a subclass to override it. - -Mocking concrete classes directly is problematic as it creates a tight -coupling between the class and the tests - any small change in the -class may invalidate your tests and make test maintenance a pain. - -To avoid such problems, many programmers have been practicing "coding -to interfaces": instead of talking to the `Concrete` class, your code -would define an interface and talk to it. Then you implement that -interface as an adaptor on top of `Concrete`. In tests, you can easily -mock that interface to observe how your code is doing. - -This technique incurs some overhead: - - * You pay the cost of virtual function calls (usually not a problem). - * There is more abstraction for the programmers to learn. - -However, it can also bring significant benefits in addition to better -testability: - - * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. - * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. - -Some people worry that if everyone is practicing this technique, they -will end up writing lots of redundant code. This concern is totally -understandable. However, there are two reasons why it may not be the -case: - - * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. - * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. - -You need to weigh the pros and cons carefully for your particular -problem, but I'd like to assure you that the Java community has been -practicing this for a long time and it's a proven effective technique -applicable in a wide variety of situations. :-) - -## Delegating Calls to a Fake ## - -Some times you have a non-trivial fake implementation of an -interface. For example: - -``` -class Foo { - public: - virtual ~Foo() {} - virtual char DoThis(int n) = 0; - virtual void DoThat(const char* s, int* p) = 0; -}; - -class FakeFoo : public Foo { - public: - virtual char DoThis(int n) { - return (n > 0) ? '+' : - (n < 0) ? '-' : '0'; - } - - virtual void DoThat(const char* s, int* p) { - *p = strlen(s); - } -}; -``` - -Now you want to mock this interface such that you can set expectations -on it. However, you also want to use `FakeFoo` for the default -behavior, as duplicating it in the mock object is, well, a lot of -work. - -When you define the mock class using Google Mock, you can have it -delegate its default action to a fake class you already have, using -this pattern: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - // Normal mock method definitions using Google Mock. - MOCK_METHOD1(DoThis, char(int n)); - MOCK_METHOD2(DoThat, void(const char* s, int* p)); - - // Delegates the default actions of the methods to a FakeFoo object. - // This must be called *before* the custom ON_CALL() statements. - void DelegateToFake() { - ON_CALL(*this, DoThis(_)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); - ON_CALL(*this, DoThat(_, _)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); - } - private: - FakeFoo fake_; // Keeps an instance of the fake in the mock. -}; -``` - -With that, you can use `MockFoo` in your tests as usual. Just remember -that if you don't explicitly set an action in an `ON_CALL()` or -`EXPECT_CALL()`, the fake will be called upon to do it: - -``` -using ::testing::_; - -TEST(AbcTest, Xyz) { - MockFoo foo; - foo.DelegateToFake(); // Enables the fake for delegation. - - // Put your ON_CALL(foo, ...)s here, if any. - - // No action specified, meaning to use the default action. - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(foo, DoThat(_, _)); - - int n = 0; - EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. - foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. - EXPECT_EQ(2, n); -} -``` - -**Some tips:** - - * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. - * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. - * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. - * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. - -Regarding the tip on mixing a mock and a fake, here's an example on -why it may be a bad sign: Suppose you have a class `System` for -low-level system operations. In particular, it does file and I/O -operations. And suppose you want to test how your code uses `System` -to do I/O, and you just want the file operations to work normally. If -you mock out the entire `System` class, you'll have to provide a fake -implementation for the file operation part, which suggests that -`System` is taking on too many roles. - -Instead, you can define a `FileOps` interface and an `IOOps` interface -and split `System`'s functionalities into the two. Then you can mock -`IOOps` without mocking `FileOps`. - -## Delegating Calls to a Real Object ## - -When using testing doubles (mocks, fakes, stubs, and etc), sometimes -their behaviors will differ from those of the real objects. This -difference could be either intentional (as in simulating an error such -that you can test the error handling code) or unintentional. If your -mocks have different behaviors than the real objects by mistake, you -could end up with code that passes the tests but fails in production. - -You can use the _delegating-to-real_ technique to ensure that your -mock has the same behavior as the real object while retaining the -ability to validate calls. This technique is very similar to the -delegating-to-fake technique, the difference being that we use a real -object instead of a fake. Here's an example: - -``` -using ::testing::_; -using ::testing::AtLeast; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MockFoo() { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DoThis()) - .WillByDefault(Invoke(&real_, &Foo::DoThis)); - ON_CALL(*this, DoThat(_)) - .WillByDefault(Invoke(&real_, &Foo::DoThat)); - ... - } - MOCK_METHOD0(DoThis, ...); - MOCK_METHOD1(DoThat, ...); - ... - private: - Foo real_; -}; -... - - MockFoo mock; - - EXPECT_CALL(mock, DoThis()) - .Times(3); - EXPECT_CALL(mock, DoThat("Hi")) - .Times(AtLeast(1)); - ... use mock in test ... -``` - -With this, Google Mock will verify that your code made the right calls -(with the right arguments, in the right order, called the right number -of times, etc), and a real object will answer the calls (so the -behavior will be the same as in production). This gives you the best -of both worlds. - -## Delegating Calls to a Parent Class ## - -Ideally, you should code to interfaces, whose methods are all pure -virtual. In reality, sometimes you do need to mock a virtual method -that is not pure (i.e, it already has an implementation). For example: - -``` -class Foo { - public: - virtual ~Foo(); - - virtual void Pure(int n) = 0; - virtual int Concrete(const char* str) { ... } -}; - -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); -}; -``` - -Sometimes you may want to call `Foo::Concrete()` instead of -`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub -action, or perhaps your test doesn't need to mock `Concrete()` at all -(but it would be oh-so painful to have to define a new mock class -whenever you don't need to mock one of its methods). - -The trick is to leave a back door in your mock class for accessing the -real methods in the base class: - -``` -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); - - // Use this to call Concrete() defined in Foo. - int FooConcrete(const char* str) { return Foo::Concrete(str); } -}; -``` - -Now, you can call `Foo::Concrete()` inside an action by: - -``` -using ::testing::_; -using ::testing::Invoke; -... - EXPECT_CALL(foo, Concrete(_)) - .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -or tell the mock object that you don't want to mock `Concrete()`: - -``` -using ::testing::Invoke; -... - ON_CALL(foo, Concrete(_)) - .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do -that, `MockFoo::Concrete()` will be called (and cause an infinite -recursion) since `Foo::Concrete()` is virtual. That's just how C++ -works.) - -# Using Matchers # - -## Matching Argument Values Exactly ## - -You can specify exactly which arguments a mock method is expecting: - -``` -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(5)) - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", bar)); -``` - -## Using Simple Matchers ## - -You can use matchers to match arguments that have a certain property: - -``` -using ::testing::Ge; -using ::testing::NotNull; -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", NotNull())); - // The second argument must not be NULL. -``` - -A frequently used matcher is `_`, which matches anything: - -``` -using ::testing::_; -using ::testing::NotNull; -... - EXPECT_CALL(foo, DoThat(_, NotNull())); -``` - -## Combining Matchers ## - -You can build complex matchers from existing ones using `AllOf()`, -`AnyOf()`, and `Not()`: - -``` -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -... - // The argument must be > 5 and != 10. - EXPECT_CALL(foo, DoThis(AllOf(Gt(5), - Ne(10)))); - - // The first argument must not contain sub-string "blah". - EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), - NULL)); -``` - -## Casting Matchers ## - -Google Mock matchers are statically typed, meaning that the compiler -can catch your mistake if you use a matcher of the wrong type (for -example, if you use `Eq(5)` to match a `string` argument). Good for -you! - -Sometimes, however, you know what you're doing and want the compiler -to give you some slack. One example is that you have a matcher for -`long` and the argument you want to match is `int`. While the two -types aren't exactly the same, there is nothing really wrong with -using a `Matcher` to match an `int` - after all, we can first -convert the `int` argument to a `long` before giving it to the -matcher. - -To support this need, Google Mock gives you the -`SafeMatcherCast(m)` function. It casts a matcher `m` to type -`Matcher`. To ensure safety, Google Mock checks that (let `U` be the -type `m` accepts): - - 1. Type `T` can be implicitly cast to type `U`; - 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and - 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). - -The code won't compile if any of these conditions isn't met. - -Here's one example: - -``` -using ::testing::SafeMatcherCast; - -// A base class and a child class. -class Base { ... }; -class Derived : public Base { ... }; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(DoThis, void(Derived* derived)); -}; -... - - MockFoo foo; - // m is a Matcher we got from somewhere. - EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); -``` - -If you find `SafeMatcherCast(m)` too limiting, you can use a similar -function `MatcherCast(m)`. The difference is that `MatcherCast` works -as long as you can `static_cast` type `T` to type `U`. - -`MatcherCast` essentially lets you bypass C++'s type system -(`static_cast` isn't always safe as it could throw away information, -for example), so be careful not to misuse/abuse it. - -## Selecting Between Overloaded Functions ## - -If you expect an overloaded function to be called, the compiler may -need some help on which overloaded version it is. - -To disambiguate functions overloaded on the const-ness of this object, -use the `Const()` argument wrapper. - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - ... - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -... - - MockFoo foo; - Bar bar1, bar2; - EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). - .WillOnce(ReturnRef(bar1)); - EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). - .WillOnce(ReturnRef(bar2)); -``` - -(`Const()` is defined by Google Mock and returns a `const` reference -to its argument.) - -To disambiguate overloaded functions with the same number of arguments -but different argument types, you may need to specify the exact type -of a matcher, either by wrapping your matcher in `Matcher()`, or -using a matcher whose type is fixed (`TypedEq`, `An()`, -etc): - -``` -using ::testing::An; -using ::testing::Lt; -using ::testing::Matcher; -using ::testing::TypedEq; - -class MockPrinter : public Printer { - public: - MOCK_METHOD1(Print, void(int n)); - MOCK_METHOD1(Print, void(char c)); -}; - -TEST(PrinterTest, Print) { - MockPrinter printer; - - EXPECT_CALL(printer, Print(An())); // void Print(int); - EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); - EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); - - printer.Print(3); - printer.Print(6); - printer.Print('a'); -} -``` - -## Performing Different Actions Based on the Arguments ## - -When a mock method is called, the _last_ matching expectation that's -still active will be selected (think "newer overrides older"). So, you -can make a method do different things depending on its argument values -like this: - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Return; -... - // The default case. - EXPECT_CALL(foo, DoThis(_)) - .WillRepeatedly(Return('b')); - - // The more specific case. - EXPECT_CALL(foo, DoThis(Lt(5))) - .WillRepeatedly(Return('a')); -``` - -Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will -be returned; otherwise `'b'` will be returned. - -## Matching Multiple Arguments as a Whole ## - -Sometimes it's not enough to match the arguments individually. For -example, we may want to say that the first argument must be less than -the second argument. The `With()` clause allows us to match -all arguments of a mock function as a whole. For example, - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Ne; -... - EXPECT_CALL(foo, InRange(Ne(0), _)) - .With(Lt()); -``` - -says that the first argument of `InRange()` must not be 0, and must be -less than the second argument. - -The expression inside `With()` must be a matcher of type -`Matcher >`, where `A1`, ..., `An` are the -types of the function arguments. - -You can also write `AllArgs(m)` instead of `m` inside `.With()`. The -two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable -than `.With(Lt())`. - -You can use `Args(m)` to match the `n` selected arguments -against `m`. For example, - -``` -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::Lt; -... - EXPECT_CALL(foo, Blah(_, _, _)) - .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); -``` - -says that `Blah()` will be called with arguments `x`, `y`, and `z` where -`x < y < z`. - -As a convenience and example, Google Mock provides some matchers for -2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_5_CheatSheet.md) for -the complete list. - -## Using Matchers as Predicates ## - -Have you noticed that a matcher is just a fancy predicate that also -knows how to describe itself? Many existing algorithms take predicates -as arguments (e.g. those defined in STL's `` header), and -it would be a shame if Google Mock matchers are not allowed to -participate. - -Luckily, you can use a matcher where a unary predicate functor is -expected by wrapping it inside the `Matches()` function. For example, - -``` -#include -#include - -std::vector v; -... -// How many elements in v are >= 10? -const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); -``` - -Since you can build complex matchers from simpler ones easily using -Google Mock, this gives you a way to conveniently construct composite -predicates (doing the same using STL's `` header is just -painful). For example, here's a predicate that's satisfied by any -number that is >= 0, <= 100, and != 50: - -``` -Matches(AllOf(Ge(0), Le(100), Ne(50))) -``` - -## Using Matchers in Google Test Assertions ## - -Since matchers are basically predicates that also know how to describe -themselves, there is a way to take advantage of them in -[Google Test](http://code.google.com/p/googletest/) assertions. It's -called `ASSERT_THAT` and `EXPECT_THAT`: - -``` - ASSERT_THAT(value, matcher); // Asserts that value matches matcher. - EXPECT_THAT(value, matcher); // The non-fatal version. -``` - -For example, in a Google Test test you can write: - -``` -#include - -using ::testing::AllOf; -using ::testing::Ge; -using ::testing::Le; -using ::testing::MatchesRegex; -using ::testing::StartsWith; -... - - EXPECT_THAT(Foo(), StartsWith("Hello")); - EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); - ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); -``` - -which (as you can probably guess) executes `Foo()`, `Bar()`, and -`Baz()`, and verifies that: - - * `Foo()` returns a string that starts with `"Hello"`. - * `Bar()` returns a string that matches regular expression `"Line \\d+"`. - * `Baz()` returns a number in the range [5, 10]. - -The nice thing about these macros is that _they read like -English_. They generate informative messages too. For example, if the -first `EXPECT_THAT()` above fails, the message will be something like: - -``` -Value of: Foo() - Actual: "Hi, world!" -Expected: starts with "Hello" -``` - -**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the -[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds -`assertThat()` to JUnit. - -## Using Predicates as Matchers ## - -Google Mock provides a built-in set of matchers. In case you find them -lacking, you can use an arbitray unary predicate function or functor -as a matcher - as long as the predicate accepts a value of the type -you want. You do this by wrapping the predicate inside the `Truly()` -function, for example: - -``` -using ::testing::Truly; - -int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } -... - - // Bar() must be called with an even number. - EXPECT_CALL(foo, Bar(Truly(IsEven))); -``` - -Note that the predicate function / functor doesn't have to return -`bool`. It works as long as the return value can be used as the -condition in statement `if (condition) ...`. - -## Matching Arguments that Are Not Copyable ## - -When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves -away a copy of `bar`. When `Foo()` is called later, Google Mock -compares the argument to `Foo()` with the saved copy of `bar`. This -way, you don't need to worry about `bar` being modified or destroyed -after the `EXPECT_CALL()` is executed. The same is true when you use -matchers like `Eq(bar)`, `Le(bar)`, and so on. - -But what if `bar` cannot be copied (i.e. has no copy constructor)? You -could define your own matcher function and use it with `Truly()`, as -the previous couple of recipes have shown. Or, you may be able to get -away from it if you can guarantee that `bar` won't be changed after -the `EXPECT_CALL()` is executed. Just tell Google Mock that it should -save a reference to `bar`, instead of a copy of it. Here's how: - -``` -using ::testing::Eq; -using ::testing::ByRef; -using ::testing::Lt; -... - // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); - - // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); -``` - -Remember: if you do this, don't change `bar` after the -`EXPECT_CALL()`, or the result is undefined. - -## Validating a Member of an Object ## - -Often a mock function takes a reference to object as an argument. When -matching the argument, you may not want to compare the entire object -against a fixed object, as that may be over-specification. Instead, -you may need to validate a certain member variable or the result of a -certain getter method of the object. You can do this with `Field()` -and `Property()`. More specifically, - -``` -Field(&Foo::bar, m) -``` - -is a matcher that matches a `Foo` object whose `bar` member variable -satisfies matcher `m`. - -``` -Property(&Foo::baz, m) -``` - -is a matcher that matches a `Foo` object whose `baz()` method returns -a value that satisfies matcher `m`. - -For example: - -> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | -|:-----------------------------|:-----------------------------------| -> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | - -Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no -argument and be declared as `const`. - -BTW, `Field()` and `Property()` can also match plain pointers to -objects. For instance, - -``` -Field(&Foo::number, Ge(3)) -``` - -matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, -the match will always fail regardless of the inner matcher. - -What if you want to validate more than one members at the same time? -Remember that there is `AllOf()`. - -## Validating the Value Pointed to by a Pointer Argument ## - -C++ functions often take pointers as arguments. You can use matchers -like `NULL`, `NotNull()`, and other comparison matchers to match a -pointer, but what if you want to make sure the value _pointed to_ by -the pointer, instead of the pointer itself, has a certain property? -Well, you can use the `Pointee(m)` matcher. - -`Pointee(m)` matches a pointer iff `m` matches the value the pointer -points to. For example: - -``` -using ::testing::Ge; -using ::testing::Pointee; -... - EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); -``` - -expects `foo.Bar()` to be called with a pointer that points to a value -greater than or equal to 3. - -One nice thing about `Pointee()` is that it treats a `NULL` pointer as -a match failure, so you can write `Pointee(m)` instead of - -``` - AllOf(NotNull(), Pointee(m)) -``` - -without worrying that a `NULL` pointer will crash your test. - -Also, did we tell you that `Pointee()` works with both raw pointers -**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and -etc)? - -What if you have a pointer to pointer? You guessed it - you can use -nested `Pointee()` to probe deeper inside the value. For example, -`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer -that points to a number less than 3 (what a mouthful...). - -## Testing a Certain Property of an Object ## - -Sometimes you want to specify that an object argument has a certain -property, but there is no existing matcher that does this. If you want -good error messages, you should define a matcher. If you want to do it -quick and dirty, you could get away with writing an ordinary function. - -Let's say you have a mock function that takes an object of type `Foo`, -which has an `int bar()` method and an `int baz()` method, and you -want to constrain that the argument's `bar()` value plus its `baz()` -value is a given number. Here's how you can define a matcher to do it: - -``` -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class BarPlusBazEqMatcher : public MatcherInterface { - public: - explicit BarPlusBazEqMatcher(int expected_sum) - : expected_sum_(expected_sum) {} - - virtual bool MatchAndExplain(const Foo& foo, - MatchResultListener* listener) const { - return (foo.bar() + foo.baz()) == expected_sum_; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "bar() + baz() equals " << expected_sum_; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "bar() + baz() does not equal " << expected_sum_; - } - private: - const int expected_sum_; -}; - -inline Matcher BarPlusBazEq(int expected_sum) { - return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); -} - -... - - EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; -``` - -## Matching Containers ## - -Sometimes an STL container (e.g. list, vector, map, ...) is passed to -a mock function and you may want to validate it. Since most STL -containers support the `==` operator, you can write -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. - -Sometimes, though, you may want to be more flexible (for example, the -first element must be an exact match, but the second element can be -any positive number, and so on). Also, containers used in tests often -have a small number of elements, and having to define the expected -container out-of-line is a bit of a hassle. - -You can use the `ElementsAre()` matcher in such cases: - -``` -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::Gt; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); -``` - -The above matcher says that the container must have 4 elements, which -must be 1, greater than 0, anything, and 5 respectively. - -`ElementsAre()` is overloaded to take 0 to 10 arguments. If more are -needed, you can place them in a C-style array and use -`ElementsAreArray()` instead: - -``` -using ::testing::ElementsAreArray; -... - - // ElementsAreArray accepts an array of element values. - const int expected_vector1[] = { 1, 5, 2, 4, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); - - // Or, an array of element matchers. - Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); -``` - -In case the array needs to be dynamically created (and therefore the -array size cannot be inferred by the compiler), you can give -`ElementsAreArray()` an additional argument to specify the array size: - -``` -using ::testing::ElementsAreArray; -... - int* const expected_vector3 = new int[count]; - ... fill expected_vector3 with values ... - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); -``` - -**Tips:** - - * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. - * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. - * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. - * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). - -## Sharing Matchers ## - -Under the hood, a Google Mock matcher object consists of a pointer to -a ref-counted implementation object. Copying matchers is allowed and -very efficient, as only the pointer is copied. When the last matcher -that references the implementation object dies, the implementation -object will be deleted. - -Therefore, if you have some complex matcher that you want to use again -and again, there is no need to build it everytime. Just assign it to a -matcher variable and use that variable repeatedly! For example, - -``` - Matcher in_range = AllOf(Gt(5), Le(10)); - ... use in_range as a matcher in multiple EXPECT_CALLs ... -``` - -# Setting Expectations # - -## Ignoring Uninteresting Calls ## - -If you are not interested in how a mock method is called, just don't -say anything about it. In this case, if the method is ever called, -Google Mock will perform its default action to allow the test program -to continue. If you are not happy with the default action taken by -Google Mock, you can override it using `DefaultValue::Set()` -(described later in this document) or `ON_CALL()`. - -Please note that once you expressed interest in a particular mock -method (via `EXPECT_CALL()`), all invocations to it must match some -expectation. If this function is called but the arguments don't match -any `EXPECT_CALL()` statement, it will be an error. - -## Disallowing Unexpected Calls ## - -If a mock method shouldn't be called at all, explicitly say so: - -``` -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -If some calls to the method are allowed, but the rest are not, just -list all the expected calls: - -``` -using ::testing::AnyNumber; -using ::testing::Gt; -... - EXPECT_CALL(foo, Bar(5)); - EXPECT_CALL(foo, Bar(Gt(10))) - .Times(AnyNumber()); -``` - -A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` -statements will be an error. - -## Expecting Ordered Calls ## - -Although an `EXPECT_CALL()` statement defined earlier takes precedence -when Google Mock tries to match a function call with an expectation, -by default calls don't have to happen in the order `EXPECT_CALL()` -statements are written. For example, if the arguments match the -matchers in the third `EXPECT_CALL()`, but not those in the first two, -then the third expectation will be used. - -If you would rather have all calls occur in the order of the -expectations, put the `EXPECT_CALL()` statements in a block where you -define a variable of type `InSequence`: - -``` - using ::testing::_; - using ::testing::InSequence; - - { - InSequence s; - - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(bar, DoThat(_)) - .Times(2); - EXPECT_CALL(foo, DoThis(6)); - } -``` - -In this example, we expect a call to `foo.DoThis(5)`, followed by two -calls to `bar.DoThat()` where the argument can be anything, which are -in turn followed by a call to `foo.DoThis(6)`. If a call occurred -out-of-order, Google Mock will report an error. - -## Expecting Partially Ordered Calls ## - -Sometimes requiring everything to occur in a predetermined order can -lead to brittle tests. For example, we may care about `A` occurring -before both `B` and `C`, but aren't interested in the relative order -of `B` and `C`. In this case, the test should reflect our real intent, -instead of being overly constraining. - -Google Mock allows you to impose an arbitrary DAG (directed acyclic -graph) on the calls. One way to express the DAG is to use the -[After](V1_5_CheatSheet#The_After_Clause.md) clause of `EXPECT_CALL`. - -Another way is via the `InSequence()` clause (not the same as the -`InSequence` class), which we borrowed from jMock 2. It's less -flexible than `After()`, but more convenient when you have long chains -of sequential calls, as it doesn't require you to come up with -different names for the expectations in the chains. Here's how it -works: - -If we view `EXPECT_CALL()` statements as nodes in a graph, and add an -edge from node A to node B wherever A must occur before B, we can get -a DAG. We use the term "sequence" to mean a directed path in this -DAG. Now, if we decompose the DAG into sequences, we just need to know -which sequences each `EXPECT_CALL()` belongs to in order to be able to -reconstruct the orginal DAG. - -So, to specify the partial order on the expectations we need to do two -things: first to define some `Sequence` objects, and then for each -`EXPECT_CALL()` say which `Sequence` objects it is part -of. Expectations in the same sequence must occur in the order they are -written. For example, - -``` - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(foo, A()) - .InSequence(s1, s2); - EXPECT_CALL(bar, B()) - .InSequence(s1); - EXPECT_CALL(bar, C()) - .InSequence(s2); - EXPECT_CALL(foo, D()) - .InSequence(s2); -``` - -specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> -C -> D`): - -``` - +---> B - | - A ---| - | - +---> C ---> D -``` - -This means that A must occur before B and C, and C must occur before -D. There's no restriction about the order other than these. - -## Controlling When an Expectation Retires ## - -When a mock method is called, Google Mock only consider expectations -that are still active. An expectation is active when created, and -becomes inactive (aka _retires_) when a call that has to occur later -has occurred. For example, in - -``` - using ::testing::_; - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 - .Times(AnyNumber()) - .InSequence(s1, s2); - EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 - .InSequence(s1); - EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 - .InSequence(s2); -``` - -as soon as either #2 or #3 is matched, #1 will retire. If a warning -`"File too large."` is logged after this, it will be an error. - -Note that an expectation doesn't retire automatically when it's -saturated. For example, - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 -``` - -says that there will be exactly one warning with the message `"File -too large."`. If the second warning contains this message too, #2 will -match again and result in an upper-bound-violated error. - -If this is not what you want, you can ask an expectation to retire as -soon as it becomes saturated: - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 - .RetiresOnSaturation(); -``` - -Here #2 can be used only once, so if you have two warnings with the -message `"File too large."`, the first will match #2 and the second -will match #1 - there will be no error. - -# Using Actions # - -## Returning References from Mock Methods ## - -If a mock function's return type is a reference, you need to use -`ReturnRef()` instead of `Return()` to return a result: - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetBar, Bar&()); -}; -... - - MockFoo foo; - Bar bar; - EXPECT_CALL(foo, GetBar()) - .WillOnce(ReturnRef(bar)); -``` - -## Combining Actions ## - -Want to do more than one thing when a function is called? That's -fine. `DoAll()` allow you to do sequence of actions every time. Only -the return value of the last action in the sequence will be used. - -``` -using ::testing::DoAll; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Bar, bool(int n)); -}; -... - - EXPECT_CALL(foo, Bar(_)) - .WillOnce(DoAll(action_1, - action_2, - ... - action_n)); -``` - -## Mocking Side Effects ## - -Sometimes a method exhibits its effect not via returning a value but -via side effects. For example, it may change some global state or -modify an output argument. To mock side effects, in general you can -define your own action by implementing `::testing::ActionInterface`. - -If all you need to do is to change an output argument, the built-in -`SetArgumentPointee()` action is convenient: - -``` -using ::testing::SetArgumentPointee; - -class MockMutator : public Mutator { - public: - MOCK_METHOD2(Mutate, void(bool mutate, int* value)); - ... -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, Mutate(true, _)) - .WillOnce(SetArgumentPointee<1>(5)); -``` - -In this example, when `mutator.Mutate()` is called, we will assign 5 -to the `int` variable pointed to by argument #1 -(0-based). - -`SetArgumentPointee()` conveniently makes an internal copy of the -value you pass to it, removing the need to keep the value in scope and -alive. The implication however is that the value must have a copy -constructor and assignment operator. - -If the mock method also needs to return a value as well, you can chain -`SetArgumentPointee()` with `Return()` using `DoAll()`: - -``` -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgumentPointee; - -class MockMutator : public Mutator { - public: - ... - MOCK_METHOD1(MutateInt, bool(int* value)); -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, MutateInt(_)) - .WillOnce(DoAll(SetArgumentPointee<0>(5), - Return(true))); -``` - -If the output argument is an array, use the -`SetArrayArgument(first, last)` action instead. It copies the -elements in source range `[first, last)` to the array pointed to by -the `N`-th (0-based) argument: - -``` -using ::testing::NotNull; -using ::testing::SetArrayArgument; - -class MockArrayMutator : public ArrayMutator { - public: - MOCK_METHOD2(Mutate, void(int* values, int num_values)); - ... -}; -... - - MockArrayMutator mutator; - int values[5] = { 1, 2, 3, 4, 5 }; - EXPECT_CALL(mutator, Mutate(NotNull(), 5)) - .WillOnce(SetArrayArgument<0>(values, values + 5)); -``` - -This also works when the argument is an output iterator: - -``` -using ::testing::_; -using ::testing::SeArrayArgument; - -class MockRolodex : public Rolodex { - public: - MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); - ... -}; -... - - MockRolodex rolodex; - vector names; - names.push_back("George"); - names.push_back("John"); - names.push_back("Thomas"); - EXPECT_CALL(rolodex, GetNames(_)) - .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); -``` - -## Changing a Mock Object's Behavior Based on the State ## - -If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: - -``` -using ::testing::InSequence; -using ::testing::Return; - -... - { - InSequence seq; - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(my_mock, Flush()); - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(false)); - } - my_mock.FlushIfDirty(); -``` - -This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. - -If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: - -``` -using ::testing::_; -using ::testing::SaveArg; -using ::testing::Return; - -ACTION_P(ReturnPointee, p) { return *p; } -... - int previous_value = 0; - EXPECT_CALL(my_mock, GetPrevValue()) - .WillRepeatedly(ReturnPointee(&previous_value)); - EXPECT_CALL(my_mock, UpdateValue(_)) - .WillRepeatedly(SaveArg<0>(&previous_value)); - my_mock.DoSomethingToUpdateValue(); -``` - -Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. - -## Setting the Default Value for a Return Type ## - -If a mock method's return type is a built-in C++ type or pointer, by -default it will return 0 when invoked. You only need to specify an -action if this default value doesn't work for you. - -Sometimes, you may want to change this default value, or you may want -to specify a default value for types Google Mock doesn't know -about. You can do this using the `::testing::DefaultValue` class -template: - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD0(CalculateBar, Bar()); -}; -... - - Bar default_bar; - // Sets the default return value for type Bar. - DefaultValue::Set(default_bar); - - MockFoo foo; - - // We don't need to specify an action here, as the default - // return value works for us. - EXPECT_CALL(foo, CalculateBar()); - - foo.CalculateBar(); // This should return default_bar. - - // Unsets the default return value. - DefaultValue::Clear(); -``` - -Please note that changing the default value for a type can make you -tests hard to understand. We recommend you to use this feature -judiciously. For example, you may want to make sure the `Set()` and -`Clear()` calls are right next to the code that uses your mock. - -## Setting the Default Actions for a Mock Method ## - -You've learned how to change the default value of a given -type. However, this may be too coarse for your purpose: perhaps you -have two mock methods with the same return type and you want them to -have different behaviors. The `ON_CALL()` macro allows you to -customize your mock's behavior at the method level: - -``` -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Gt; -using ::testing::Return; -... - ON_CALL(foo, Sign(_)) - .WillByDefault(Return(-1)); - ON_CALL(foo, Sign(0)) - .WillByDefault(Return(0)); - ON_CALL(foo, Sign(Gt(0))) - .WillByDefault(Return(1)); - - EXPECT_CALL(foo, Sign(_)) - .Times(AnyNumber()); - - foo.Sign(5); // This should return 1. - foo.Sign(-9); // This should return -1. - foo.Sign(0); // This should return 0. -``` - -As you may have guessed, when there are more than one `ON_CALL()` -statements, the news order take precedence over the older ones. In -other words, the **last** one that matches the function arguments will -be used. This matching order allows you to set up the common behavior -in a mock object's constructor or the test fixture's set-up phase and -specialize the mock's behavior later. - -## Using Functions/Methods/Functors as Actions ## - -If the built-in actions don't suit you, you can easily use an existing -function, method, or functor as an action: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(Sum, int(int x, int y)); - MOCK_METHOD1(ComplexJob, bool(int x)); -}; - -int CalculateSum(int x, int y) { return x + y; } - -class Helper { - public: - bool ComplexJob(int x); -}; -... - - MockFoo foo; - Helper helper; - EXPECT_CALL(foo, Sum(_, _)) - .WillOnce(Invoke(CalculateSum)); - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(Invoke(&helper, &Helper::ComplexJob)); - - foo.Sum(5, 6); // Invokes CalculateSum(5, 6). - foo.ComplexJob(10); // Invokes helper.ComplexJob(10); -``` - -The only requirement is that the type of the function, etc must be -_compatible_ with the signature of the mock function, meaning that the -latter's arguments can be implicitly converted to the corresponding -arguments of the former, and the former's return type can be -implicitly converted to that of the latter. So, you can invoke -something whose type is _not_ exactly the same as the mock function, -as long as it's safe to do so - nice, huh? - -## Invoking a Function/Method/Functor Without Arguments ## - -`Invoke()` is very useful for doing actions that are more complex. It -passes the mock function's arguments to the function or functor being -invoked such that the callee has the full context of the call to work -with. If the invoked function is not interested in some or all of the -arguments, it can simply ignore them. - -Yet, a common pattern is that a test author wants to invoke a function -without the arguments of the mock function. `Invoke()` allows her to -do that using a wrapper function that throws away the arguments before -invoking an underlining nullary function. Needless to say, this can be -tedious and obscures the intent of the test. - -`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except -that it doesn't pass the mock function's arguments to the -callee. Here's an example: - -``` -using ::testing::_; -using ::testing::InvokeWithoutArgs; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(ComplexJob, bool(int n)); -}; - -bool Job1() { ... } -... - - MockFoo foo; - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(InvokeWithoutArgs(Job1)); - - foo.ComplexJob(10); // Invokes Job1(). -``` - -## Invoking an Argument of the Mock Function ## - -Sometimes a mock function will receive a function pointer or a functor -(in other words, a "callable") as an argument, e.g. - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); -}; -``` - -and you may want to invoke this callable argument: - -``` -using ::testing::_; -... - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(...); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -Arghh, you need to refer to a mock function argument but C++ has no -lambda (yet), so you have to define your own action. :-( Or do you -really? - -Well, Google Mock has an action to solve _exactly_ this problem: - -``` - InvokeArgument(arg_1, arg_2, ..., arg_m) -``` - -will invoke the `N`-th (0-based) argument the mock function receives, -with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is -a function pointer or a functor, Google Mock handles them both. - -With that, you could write: - -``` -using ::testing::_; -using ::testing::InvokeArgument; -... - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(InvokeArgument<1>(5)); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -What if the callable takes an argument by reference? No problem - just -wrap it inside `ByRef()`: - -``` -... - MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); -... -using ::testing::_; -using ::testing::ByRef; -using ::testing::InvokeArgument; -... - - MockFoo foo; - Helper helper; - ... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, ByRef(helper))); - // ByRef(helper) guarantees that a reference to helper, not a copy of it, - // will be passed to the callable. -``` - -What if the callable takes an argument by reference and we do **not** -wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a -copy_ of the argument, and pass a _reference to the copy_, instead of -a reference to the original value, to the callable. This is especially -handy when the argument is a temporary value: - -``` -... - MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); -... -using ::testing::_; -using ::testing::InvokeArgument; -... - - MockFoo foo; - ... - EXPECT_CALL(foo, DoThat(_)) - .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); - // Will execute (*f)(5.0, string("Hi")), where f is the function pointer - // DoThat() receives. Note that the values 5.0 and string("Hi") are - // temporary and dead once the EXPECT_CALL() statement finishes. Yet - // it's fine to perform this action later, since a copy of the values - // are kept inside the InvokeArgument action. -``` - -## Ignoring an Action's Result ## - -Sometimes you have an action that returns _something_, but you need an -action that returns `void` (perhaps you want to use it in a mock -function that returns `void`, or perhaps it needs to be used in -`DoAll()` and it's not the last in the list). `IgnoreResult()` lets -you do that. For example: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; - -int Process(const MyData& data); -string DoSomething(); - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Abc, void(const MyData& data)); - MOCK_METHOD0(Xyz, bool()); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, Abc(_)) - // .WillOnce(Invoke(Process)); - // The above line won't compile as Process() returns int but Abc() needs - // to return void. - .WillOnce(IgnoreResult(Invoke(Process))); - - EXPECT_CALL(foo, Xyz()) - .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), - // Ignores the string DoSomething() returns. - Return(true))); -``` - -Note that you **cannot** use `IgnoreResult()` on an action that already -returns `void`. Doing so will lead to ugly compiler errors. - -## Selecting an Action's Arguments ## - -Say you have a mock function `Foo()` that takes seven arguments, and -you have a custom action that you want to invoke when `Foo()` is -called. Trouble is, the custom action only wants three arguments: - -``` -using ::testing::_; -using ::testing::Invoke; -... - MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight)); -... - -bool IsVisibleInQuadrant1(bool visible, int x, int y) { - return visible && x >= 0 && y >= 0; -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( -``` - -To please the compiler God, you can to define an "adaptor" that has -the same signature as `Foo()` and calls the custom action with the -right arguments: - -``` -using ::testing::_; -using ::testing::Invoke; - -bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight) { - return IsVisibleInQuadrant1(visible, x, y); -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. -``` - -But isn't this awkward? - -Google Mock provides a generic _action adaptor_, so you can spend your -time minding more important business than writing your own -adaptors. Here's the syntax: - -``` - WithArgs(action) -``` - -creates an action that passes the arguments of the mock function at -the given indices (0-based) to the inner `action` and performs -it. Using `WithArgs`, our original example can be written as: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::WithArgs; -... - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); - // No need to define your own adaptor. -``` - -For better readability, Google Mock also gives you: - - * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and - * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. - -As you may have realized, `InvokeWithoutArgs(...)` is just syntactic -sugar for `WithoutArgs(Inovke(...))`. - -Here are more tips: - - * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. - * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. - * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. - * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. - -## Ignoring Arguments in Action Functions ## - -The selecting-an-action's-arguments recipe showed us one way to make a -mock function and an action with incompatible argument lists fit -together. The downside is that wrapping the action in -`WithArgs<...>()` can get tedious for people writing the tests. - -If you are defining a function, method, or functor to be used with -`Invoke*()`, and you are not interested in some of its arguments, an -alternative to `WithArgs` is to declare the uninteresting arguments as -`Unused`. This makes the definition less cluttered and less fragile in -case the types of the uninteresting arguments change. It could also -increase the chance the action function can be reused. For example, -given - -``` - MOCK_METHOD3(Foo, double(const string& label, double x, double y)); - MOCK_METHOD3(Bar, double(int index, double x, double y)); -``` - -instead of - -``` -using ::testing::_; -using ::testing::Invoke; - -double DistanceToOriginWithLabel(const string& label, double x, double y) { - return sqrt(x*x + y*y); -} - -double DistanceToOriginWithIndex(int index, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOriginWithLabel)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOriginWithIndex)); -``` - -you could write - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Unused; - -double DistanceToOrigin(Unused, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOrigin)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOrigin)); -``` - -## Sharing Actions ## - -Just like matchers, a Google Mock action object consists of a pointer -to a ref-counted implementation object. Therefore copying actions is -also allowed and very efficient. When the last action that references -the implementation object dies, the implementation object will be -deleted. - -If you have some complex action that you want to use again and again, -you may not have to build it from scratch everytime. If the action -doesn't have an internal state (i.e. if it always does the same thing -no matter how many times it has been called), you can assign it to an -action variable and use that variable repeatedly. For example: - -``` - Action set_flag = DoAll(SetArgumentPointee<0>(5), - Return(true)); - ... use set_flag in .WillOnce() and .WillRepeatedly() ... -``` - -However, if the action has its own state, you may be surprised if you -share the action object. Suppose you have an action factory -`IncrementCounter(init)` which creates an action that increments and -returns a counter whose initial value is `init`, using two actions -created from the same expression and using a shared action will -exihibit different behaviors. Example: - -``` - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(IncrementCounter(0)); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(IncrementCounter(0)); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 1 - Blah() uses a different - // counter than Bar()'s. -``` - -versus - -``` - Action increment = IncrementCounter(0); - - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(increment); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(increment); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 3 - the counter is shared. -``` - -# Misc Recipes on Using Google Mock # - -## Forcing a Verification ## - -When it's being destoyed, your friendly mock object will automatically -verify that all expectations on it have been satisfied, and will -generate [Google Test](http://code.google.com/p/googletest/) failures -if not. This is convenient as it leaves you with one less thing to -worry about. That is, unless you are not sure if your mock object will -be destoyed. - -How could it be that your mock object won't eventually be destroyed? -Well, it might be created on the heap and owned by the code you are -testing. Suppose there's a bug in that code and it doesn't delete the -mock object properly - you could end up with a passing test when -there's actually a bug. - -Using a heap checker is a good idea and can alleviate the concern, but -its implementation may not be 100% reliable. So, sometimes you do want -to _force_ Google Mock to verify a mock object before it is -(hopefully) destructed. You can do this with -`Mock::VerifyAndClearExpectations(&mock_object)`: - -``` -TEST(MyServerTest, ProcessesRequest) { - using ::testing::Mock; - - MockFoo* const foo = new MockFoo; - EXPECT_CALL(*foo, ...)...; - // ... other expectations ... - - // server now owns foo. - MyServer server(foo); - server.ProcessRequest(...); - - // In case that server's destructor will forget to delete foo, - // this will verify the expectations anyway. - Mock::VerifyAndClearExpectations(foo); -} // server is destroyed when it goes out of scope here. -``` - -**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a -`bool` to indicate whether the verification was successful (`true` for -yes), so you can wrap that function call inside a `ASSERT_TRUE()` if -there is no point going further when the verification has failed. - -## Using Check Points ## - -Sometimes you may want to "reset" a mock object at various check -points in your test: at each check point, you verify that all existing -expectations on the mock object have been satisfied, and then you set -some new expectations on it as if it's newly created. This allows you -to work with a mock object in "phases" whose sizes are each -manageable. - -One such scenario is that in your test's `SetUp()` function, you may -want to put the object you are testing into a certain state, with the -help from a mock object. Once in the desired state, you want to clear -all expectations on the mock, such that in the `TEST_F` body you can -set fresh expectations on it. - -As you may have figured out, the `Mock::VerifyAndClearExpectations()` -function we saw in the previous recipe can help you here. Or, if you -are using `ON_CALL()` to set default actions on the mock object and -want to clear the default actions as well, use -`Mock::VerifyAndClear(&mock_object)` instead. This function does what -`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the -same `bool`, **plus** it clears the `ON_CALL()` statements on -`mock_object` too. - -Another trick you can use to achieve the same effect is to put the -expectations in sequences and insert calls to a dummy "check-point" -function at specific places. Then you can verify that the mock -function calls do happen at the right time. For example, if you are -exercising code: - -``` -Foo(1); -Foo(2); -Foo(3); -``` - -and want to verify that `Foo(1)` and `Foo(3)` both invoke -`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: - -``` -using ::testing::MockFunction; - -TEST(FooTest, InvokesBarCorrectly) { - MyMock mock; - // Class MockFunction has exactly one mock method. It is named - // Call() and has type F. - MockFunction check; - { - InSequence s; - - EXPECT_CALL(mock, Bar("a")); - EXPECT_CALL(check, Call("1")); - EXPECT_CALL(check, Call("2")); - EXPECT_CALL(mock, Bar("a")); - } - Foo(1); - check.Call("1"); - Foo(2); - check.Call("2"); - Foo(3); -} -``` - -The expectation spec says that the first `Bar("a")` must happen before -check point "1", the second `Bar("a")` must happen after check point "2", -and nothing should happen between the two check points. The explicit -check points make it easy to tell which `Bar("a")` is called by which -call to `Foo()`. - -## Mocking Destructors ## - -Sometimes you want to make sure a mock object is destructed at the -right time, e.g. after `bar->A()` is called but before `bar->B()` is -called. We already know that you can specify constraints on the order -of mock function calls, so all we need to do is to mock the destructor -of the mock function. - -This sounds simple, except for one problem: a destructor is a special -function with special syntax and special semantics, and the -`MOCK_METHOD0` macro doesn't work for it: - -``` - MOCK_METHOD0(~MockFoo, void()); // Won't compile! -``` - -The good news is that you can use a simple pattern to achieve the same -effect. First, add a mock function `Die()` to your mock class and call -it in the destructor, like this: - -``` -class MockFoo : public Foo { - ... - // Add the following two lines to the mock class. - MOCK_METHOD0(Die, void()); - virtual ~MockFoo() { Die(); } -}; -``` - -(If the name `Die()` clashes with an existing symbol, choose another -name.) Now, we have translated the problem of testing when a `MockFoo` -object dies to testing when its `Die()` method is called: - -``` - MockFoo* foo = new MockFoo; - MockBar* bar = new MockBar; - ... - { - InSequence s; - - // Expects *foo to die after bar->A() and before bar->B(). - EXPECT_CALL(*bar, A()); - EXPECT_CALL(*foo, Die()); - EXPECT_CALL(*bar, B()); - } -``` - -And that's that. - -## Using Google Mock and Threads ## - -**IMPORTANT NOTE:** What we describe in this recipe is **NOT** true yet, -as Google Mock is not currently thread-safe. However, all we need to -make it thread-safe is to implement some synchronization operations in -`` - and then the information below will -become true. - -In a **unit** test, it's best if you could isolate and test a piece of -code in a single-threaded context. That avoids race conditions and -dead locks, and makes debugging your test much easier. - -Yet many programs are multi-threaded, and sometimes to test something -we need to pound on it from more than one thread. Google Mock works -for this purpose too. - -Remember the steps for using a mock: - - 1. Create a mock object `foo`. - 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. - 1. The code under test calls methods of `foo`. - 1. Optionally, verify and reset the mock. - 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. - -If you follow the following simple rules, your mocks and threads can -live happily togeter: - - * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. - * Obviously, you can do step #1 without locking. - * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? - * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. - -If you violate the rules (for example, if you set expectations on a -mock while another thread is calling its methods), you get undefined -behavior. That's not fun, so don't do it. - -Google Mock guarantees that the action for a mock function is done in -the same thread that called the mock function. For example, in - -``` - EXPECT_CALL(mock, Foo(1)) - .WillOnce(action1); - EXPECT_CALL(mock, Foo(2)) - .WillOnce(action2); -``` - -if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, -Google Mock will execute `action1` in thread 1 and `action2` in thread -2. - -Google Mock does _not_ impose a sequence on actions performed in -different threads (doing so may create deadlocks as the actions may -need to cooperate). This means that the execution of `action1` and -`action2` in the above example _may_ interleave. If this is a problem, -you should add proper synchronization logic to `action1` and `action2` -to make the test thread-safe. - - -Also, remember that `DefaultValue` is a global resource that -potentially affects _all_ living mock objects in your -program. Naturally, you won't want to mess with it from multiple -threads or when there still are mocks in action. - -## Controlling How Much Information Google Mock Prints ## - -When Google Mock sees something that has the potential of being an -error (e.g. a mock function with no expectation is called, a.k.a. an -uninteresting call, which is allowed but perhaps you forgot to -explicitly ban the call), it prints some warning messages, including -the arguments of the function and the return value. Hopefully this -will remind you to take a look and see if there is indeed a problem. - -Sometimes you are confident that your tests are correct and may not -appreciate such friendly messages. Some other times, you are debugging -your tests or learning about the behavior of the code you are testing, -and wish you could observe every mock call that happens (including -argument values and the return value). Clearly, one size doesn't fit -all. - -You can control how much Google Mock tells you using the -`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string -with three possible values: - - * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. - * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. - * `error`: Google Mock will print errors only (least verbose). - -Alternatively, you can adjust the value of that flag from within your -tests like so: - -``` - ::testing::FLAGS_gmock_verbose = "error"; -``` - -Now, judiciously use the right flag to enable Google Mock serve you better! - -## Running Tests in Emacs ## - -If you build and run your tests in Emacs, the source file locations of -Google Mock and [Google Test](http://code.google.com/p/googletest/) -errors will be highlighted. Just press `` on one of them and -you'll be taken to the offending line. Or, you can just type `C-x `` -to jump to the next error. - -To make it even easier, you can add the following lines to your -`~/.emacs` file: - -``` -(global-set-key "\M-m" 'compile) ; m is for make -(global-set-key [M-down] 'next-error) -(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) -``` - -Then you can type `M-m` to start a build, or `M-up`/`M-down` to move -back and forth between errors. - -## Fusing Google Mock Source Files ## - -Google Mock's implementation consists of dozens of files (excluding -its own tests). Sometimes you may want them to be packaged up in -fewer files instead, such that you can easily copy them to a new -machine and start hacking there. For this we provide an experimental -Python script `fuse_gmock_files.py` in the `scripts/` directory -(starting with release 1.2.0). Assuming you have Python 2.4 or above -installed on your machine, just go to that directory and run -``` -python fuse_gmock_files.py OUTPUT_DIR -``` - -and you should see an `OUTPUT_DIR` directory being created with files -`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. -These three files contain everything you need to use Google Mock (and -Google Test). Just copy them to anywhere you want and you are ready -to write tests and use mocks. You can use the -[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests -against them. - -# Extending Google Mock # - -## Writing New Matchers Quickly ## - -The `MATCHER*` family of macros can be used to define custom matchers -easily. The syntax: - -``` -MATCHER(name, "description string") { statements; } -``` - -will define a matcher with the given name that executes the -statements, which must return a `bool` to indicate if the match -succeeds. Inside the statements, you can refer to the value being -matched by `arg`, and refer to its type by `arg_type`. - -The description string documents what the matcher does, and is used to -generate the failure message when the match fails. Since a -`MATCHER()` is usually defined in a header file shared by multiple C++ -source files, we require the description to be a C-string _literal_ to -avoid possible side effects. It can be empty (`""`), in which case -Google Mock will use the sequence of words in the matcher name as the -description. - -For example: -``` -MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } -``` -allows you to write -``` - // Expects mock_foo.Bar(n) to be called where n is divisible by 7. - EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); -``` -or, -``` - // Verifies that the value of some_expression is divisible by 7. - EXPECT_THAT(some_expression, IsDivisibleBy7()); -``` -If the above assertion fails, it will print something like: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 -``` -where the description `"is divisible by 7"` is automatically calculated from the -matcher name `IsDivisibleBy7`. - -Optionally, you can stream additional information to a hidden argument -named `result_listener` to explain the match result. For example, a -better definition of `IsDivisibleBy7` is: -``` -MATCHER(IsDivisibleBy7, "") { - if ((arg % 7) == 0) - return true; - - *result_listener << "the remainder is " << (arg % 7); - return false; -} -``` - -With this definition, the above assertion will give a better message: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 (the remainder is 6) -``` - -You should let `MatchAndExplain()` print _any additional information_ -that can help a user understand the match result. Note that it should -explain why the match succeeds in case of a success (unless it's -obvious) - this is useful when the matcher is used inside -`Not()`. There is no need to print the argument value itself, as -Google Mock already prints it for you. - -**Notes:** - - 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. - 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. - -## Writing New Parameterized Matchers Quickly ## - -Sometimes you'll want to define a matcher that has parameters. For that you -can use the macro: -``` -MATCHER_P(name, param_name, "description string") { statements; } -``` - -For example: -``` -MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -``` -will allow you to write: -``` - EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -``` -which may lead to this message (assuming `n` is 10): -``` - Value of: Blah("a") - Expected: has absolute value 10 - Actual: -9 -``` - -Note that both the matcher description and its parameter are -printed, making the message human-friendly. - -In the matcher definition body, you can write `foo_type` to -reference the type of a parameter named `foo`. For example, in the -body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write -`value_type` to refer to the type of `value`. - -Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to -`MATCHER_P10` to support multi-parameter matchers: -``` -MATCHER_Pk(name, param_1, ..., param_k, "description string") { statements; } -``` - -Please note that the custom description string is for a particular -**instance** of the matcher, where the parameters have been bound to -actual values. Therefore usually you'll want the parameter values to -be part of the description. Google Mock lets you do that using -Python-style interpolations. The following syntaxes are supported -currently: - -| `%%` | a single `%` character | -|:-----|:-----------------------| -| `%(*)s` | all parameters of the matcher printed as a tuple | -| `%(foo)s` | value of the matcher parameter named `foo` | - -For example, -``` - MATCHER_P2(InClosedRange, low, hi, "is in range [%(low)s, %(hi)s]") { - return low <= arg && arg <= hi; - } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the message: -``` - Expected: is in range [4, 6] -``` - -If you specify `""` as the description, the failure message will -contain the sequence of words in the matcher name followed by the -parameter values printed as a tuple. For example, -``` - MATCHER_P2(InClosedRange, low, hi, "") { ... } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the text: -``` - Expected: in closed range (4, 6) -``` - -For the purpose of typing, you can view -``` -MATCHER_Pk(Foo, p1, ..., pk, "description string") { ... } -``` -as shorthand for -``` -template -FooMatcherPk -Foo(p1_type p1, ..., pk_type pk) { ... } -``` - -When you write `Foo(v1, ..., vk)`, the compiler infers the types of -the parameters `v1`, ..., and `vk` for you. If you are not happy with -the result of the type inference, you can specify the types by -explicitly instantiating the template, as in `Foo(5, false)`. -As said earlier, you don't get to (or need to) specify -`arg_type` as that's determined by the context in which the matcher -is used. - -You can assign the result of expression `Foo(p1, ..., pk)` to a -variable of type `FooMatcherPk`. This can be -useful when composing matchers. Matchers that don't have a parameter -or have only one parameter have special types: you can assign `Foo()` -to a `FooMatcher`-typed variable, and assign `Foo(p)` to a -`FooMatcherP`-typed variable. - -While you can instantiate a matcher template with reference types, -passing the parameters by pointer usually makes your code more -readable. If, however, you still want to pass a parameter by -reference, be aware that in the failure message generated by the -matcher you will see the value of the referenced object but not its -address. - -You can overload matchers with different numbers of parameters: -``` -MATCHER_P(Blah, a, "description string 1") { ... } -MATCHER_P2(Blah, a, b, "description string 2") { ... } -``` - -While it's tempting to always use the `MATCHER*` macros when defining -a new matcher, you should also consider implementing -`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see -the recipes that follow), especially if you need to use the matcher a -lot. While these approaches require more work, they give you more -control on the types of the value being matched and the matcher -parameters, which in general leads to better compiler error messages -that pay off in the long run. They also allow overloading matchers -based on parameter types (as opposed to just based on the number of -parameters). - -## Writing New Monomorphic Matchers ## - -A matcher of argument type `T` implements -`::testing::MatcherInterface` and does two things: it tests whether a -value of type `T` matches the matcher, and can describe what kind of -values it matches. The latter ability is used for generating readable -error messages when expectations are violated. - -The interface looks like this: - -``` -class MatchResultListener { - public: - ... - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x); - - // Returns the underlying ostream. - ::std::ostream* stream(); -}; - -template -class MatcherInterface { - public: - virtual ~MatcherInterface(); - - // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Describes this matcher to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. - virtual void DescribeNegationTo(::std::ostream* os) const; -}; -``` - -If you need a custom matcher but `Truly()` is not a good option (for -example, you may not be happy with the way `Truly(predicate)` -describes itself, or you may want your matcher to be polymorphic as -`Eq(value)` is), you can define a matcher to do whatever you want in -two steps: first implement the matcher interface, and then define a -factory function to create a matcher instance. The second step is not -strictly needed but it makes the syntax of using the matcher nicer. - -For example, you can define a matcher to test whether an `int` is -divisible by 7 and then use it like this: -``` -using ::testing::MakeMatcher; -using ::testing::Matcher; -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { - return (n % 7) == 0; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is divisible by 7"; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "is not divisible by 7"; - } -}; - -inline Matcher DivisibleBy7() { - return MakeMatcher(new DivisibleBy7Matcher); -} -... - - EXPECT_CALL(foo, Bar(DivisibleBy7())); -``` - -You may improve the matcher message by streaming additional -information to the `listener` argument in `MatchAndExplain()`: - -``` -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, - MatchResultListener* listener) const { - const int remainder = n % 7; - if (remainder != 0) { - *listener << "the remainder is " << remainder; - } - return remainder == 0; - } - ... -}; -``` - -Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: -``` -Value of: x -Expected: is divisible by 7 - Actual: 23 (the remainder is 2) -``` - -## Writing New Polymorphic Matchers ## - -You've learned how to write your own matchers in the previous -recipe. Just one problem: a matcher created using `MakeMatcher()` only -works for one particular type of arguments. If you want a -_polymorphic_ matcher that works with arguments of several types (for -instance, `Eq(x)` can be used to match a `value` as long as `value` == -`x` compiles -- `value` and `x` don't have to share the same type), -you can learn the trick from `` but it's a bit -involved. - -Fortunately, most of the time you can define a polymorphic matcher -easily with the help of `MakePolymorphicMatcher()`. Here's how you can -define `NotNull()` as an example: - -``` -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -using ::testing::NotNull; -using ::testing::PolymorphicMatcher; - -class NotNullMatcher { - public: - // To implement a polymorphic matcher, first define a COPYABLE class - // that has three members MatchAndExplain(), DescribeTo(), and - // DescribeNegationTo(), like the following. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, - MatchResultListener* /* listener */) const { - return p != NULL; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } -}; - -// To construct a polymorphic matcher, pass an instance of the class -// to MakePolymorphicMatcher(). Note the return type. -inline PolymorphicMatcher NotNull() { - return MakePolymorphicMatcher(NotNullMatcher()); -} -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -**Note:** Your polymorphic matcher class does **not** need to inherit from -`MatcherInterface` or any other class, and its methods do **not** need -to be virtual. - -Like in a monomorphic matcher, you may explain the match result by -streaming additional information to the `listener` argument in -`MatchAndExplain()`. - -## Writing New Cardinalities ## - -A cardinality is used in `Times()` to tell Google Mock how many times -you expect a call to occur. It doesn't have to be exact. For example, -you can say `AtLeast(5)` or `Between(2, 4)`. - -If the built-in set of cardinalities doesn't suit you, you are free to -define your own by implementing the following interface (in namespace -`testing`): - -``` -class CardinalityInterface { - public: - virtual ~CardinalityInterface(); - - // Returns true iff call_count calls will satisfy this cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; -}; -``` - -For example, to specify that a call must occur even number of times, -you can write - -``` -using ::testing::Cardinality; -using ::testing::CardinalityInterface; -using ::testing::MakeCardinality; - -class EvenNumberCardinality : public CardinalityInterface { - public: - virtual bool IsSatisfiedByCallCount(int call_count) const { - return (call_count % 2) == 0; - } - - virtual bool IsSaturatedByCallCount(int call_count) const { - return false; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "called even number of times"; - } -}; - -Cardinality EvenNumber() { - return MakeCardinality(new EvenNumberCardinality); -} -... - - EXPECT_CALL(foo, Bar(3)) - .Times(EvenNumber()); -``` - -## Writing New Actions Quickly ## - -If the built-in actions don't work for you, and you find it -inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` -family to quickly define a new action that can be used in your code as -if it's a built-in action. - -By writing -``` -ACTION(name) { statements; } -``` -in a namespace scope (i.e. not inside a class or function), you will -define an action with the given name that executes the statements. -The value returned by `statements` will be used as the return value of -the action. Inside the statements, you can refer to the K-th -(0-based) argument of the mock function as `argK`. For example: -``` -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -``` -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function -arguments. Rest assured that your code is type-safe though: -you'll get a compiler error if `*arg1` doesn't support the `++` -operator, or if the type of `++(*arg1)` isn't compatible with the mock -function's return type. - -Another example: -``` -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` -defines an action `Foo()` that invokes argument #2 (a function pointer) -with 5, calls function `Blah()`, sets the value pointed to by argument -#1 to 0, and returns argument #0. - -For more convenience and flexibility, you can also use the following -pre-defined symbols in the body of `ACTION`: - -| `argK_type` | The type of the K-th (0-based) argument of the mock function | -|:------------|:-------------------------------------------------------------| -| `args` | All arguments of the mock function as a tuple | -| `args_type` | The type of all arguments of the mock function as a tuple | -| `return_type` | The return type of the mock function | -| `function_type` | The type of the mock function | - -For example, when using an `ACTION` as a stub action for mock function: -``` -int DoSomething(bool flag, int* ptr); -``` -we have: -| **Pre-defined Symbol** | **Is Bound To** | -|:-----------------------|:----------------| -| `arg0` | the value of `flag` | -| `arg0_type` | the type `bool` | -| `arg1` | the value of `ptr` | -| `arg1_type` | the type `int*` | -| `args` | the tuple `(flag, ptr)` | -| `args_type` | the type `std::tr1::tuple` | -| `return_type` | the type `int` | -| `function_type` | the type `int(bool, int*)` | - -## Writing New Parameterized Actions Quickly ## - -Sometimes you'll want to parameterize an action you define. For that -we have another macro -``` -ACTION_P(name, param) { statements; } -``` - -For example, -``` -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -``` -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term _arguments_ for the values used to -invoke the mock function, and the term _parameters_ for the values -used to instantiate an action. - -Note that you don't need to provide the type of the parameter either. -Suppose the parameter is named `param`, you can also use the -Google-Mock-defined symbol `param_type` to refer to the type of the -parameter as inferred by the compiler. For example, in the body of -`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. - -Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support -multi-parameter actions. For example, -``` -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -``` -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the -number of parameters is 0. - -You can also easily define actions overloaded on the number of parameters: -``` -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -## Restricting the Type of an Argument or Parameter in an ACTION ## - -For maximum brevity and reusability, the `ACTION*` macros don't ask -you to provide the types of the mock function arguments and the action -parameters. Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. -There are several tricks to do that. For example: -``` -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` -where `StaticAssertTypeEq` is a compile-time assertion in Google Test -that verifies two types are the same. - -## Writing New Action Templates Quickly ## - -Sometimes you want to give an action explicit template parameters that -cannot be inferred from its value parameters. `ACTION_TEMPLATE()` -supports that and can be viewed as an extension to `ACTION()` and -`ACTION_P*()`. - -The syntax: -``` -ACTION_TEMPLATE(ActionName, - HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), - AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -``` - -defines an action template that takes _m_ explicit template parameters -and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is -between 0 and 10. `name_i` is the name of the i-th template -parameter, and `kind_i` specifies whether it's a `typename`, an -integral constant, or a template. `p_i` is the name of the i-th value -parameter. - -Example: -``` -// DuplicateArg(output) converts the k-th argument of the mock -// function to type T and copies it to *output. -ACTION_TEMPLATE(DuplicateArg, - // Note the comma between int and k: - HAS_2_TEMPLATE_PARAMS(int, k, typename, T), - AND_1_VALUE_PARAMS(output)) { - *output = T(std::tr1::get(args)); -} -``` - -To create an instance of an action template, write: -``` - ActionName(v1, ..., v_n) -``` -where the `t`s are the template arguments and the -`v`s are the value arguments. The value argument -types are inferred by the compiler. For example: -``` -using ::testing::_; -... - int n; - EXPECT_CALL(mock, Foo(_, _)) - .WillOnce(DuplicateArg<1, unsigned char>(&n)); -``` - -If you want to explicitly specify the value argument types, you can -provide additional template arguments: -``` - ActionName(v1, ..., v_n) -``` -where `u_i` is the desired type of `v_i`. - -`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the -number of value parameters, but not on the number of template -parameters. Without the restriction, the meaning of the following is -unclear: - -``` - OverloadedAction(x); -``` - -Are we using a single-template-parameter action where `bool` refers to -the type of `x`, or a two-template-parameter action where the compiler -is asked to infer the type of `x`? - -## Using the ACTION Object's Type ## - -If you are writing a function that returns an `ACTION` object, you'll -need to know its type. The type depends on the macro used to define -the action and the parameter types. The rule is relatively simple: -| **Given Definition** | **Expression** | **Has Type** | -|:---------------------|:---------------|:-------------| -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | -| ... | ... | ... | - -Note that we have to pick different suffixes (`Action`, `ActionP`, -`ActionP2`, and etc) for actions with different numbers of value -parameters, or the action definitions cannot be overloaded on the -number of them. - -## Writing New Monomorphic Actions ## - -While the `ACTION*` macros are very convenient, sometimes they are -inappropriate. For example, despite the tricks shown in the previous -recipes, they don't let you directly specify the types of the mock -function arguments and the action parameters, which in general leads -to unoptimized compiler error messages that can baffle unfamiliar -users. They also don't allow overloading actions based on parameter -types without jumping through some hoops. - -An alternative to the `ACTION*` macros is to implement -`::testing::ActionInterface`, where `F` is the type of the mock -function in which the action will be used. For example: - -``` -template class ActionInterface { - public: - virtual ~ActionInterface(); - - // Performs the action. Result is the return type of function type - // F, and ArgumentTuple is the tuple of arguments of F. - // - // For example, if F is int(bool, const string&), then Result would - // be int, and ArgumentTuple would be tr1::tuple. - virtual Result Perform(const ArgumentTuple& args) = 0; -}; - -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::MakeAction; - -typedef int IncrementMethod(int*); - -class IncrementArgumentAction : public ActionInterface { - public: - virtual int Perform(const tr1::tuple& args) { - int* p = tr1::get<0>(args); // Grabs the first argument. - return *p++; - } -}; - -Action IncrementArgument() { - return MakeAction(new IncrementArgumentAction); -} -... - - EXPECT_CALL(foo, Baz(_)) - .WillOnce(IncrementArgument()); - - int n = 5; - foo.Baz(&n); // Should return 5 and change n to 6. -``` - -## Writing New Polymorphic Actions ## - -The previous recipe showed you how to define your own action. This is -all good, except that you need to know the type of the function in -which the action will be used. Sometimes that can be a problem. For -example, if you want to use the action in functions with _different_ -types (e.g. like `Return()` and `SetArgumentPointee()`). - -If an action can be used in several types of mock functions, we say -it's _polymorphic_. The `MakePolymorphicAction()` function template -makes it easy to define such an action: - -``` -namespace testing { - -template -PolymorphicAction MakePolymorphicAction(const Impl& impl); - -} // namespace testing -``` - -As an example, let's define an action that returns the second argument -in the mock function's argument list. The first step is to define an -implementation class: - -``` -class ReturnSecondArgumentAction { - public: - template - Result Perform(const ArgumentTuple& args) const { - // To get the i-th (0-based) argument, use tr1::get(args). - return tr1::get<1>(args); - } -}; -``` - -This implementation class does _not_ need to inherit from any -particular class. What matters is that it must have a `Perform()` -method template. This method template takes the mock function's -arguments as a tuple in a **single** argument, and returns the result of -the action. It can be either `const` or not, but must be invokable -with exactly one template argument, which is the result type. In other -words, you must be able to call `Perform(args)` where `R` is the -mock function's return type and `args` is its arguments in a tuple. - -Next, we use `MakePolymorphicAction()` to turn an instance of the -implementation class into the polymorphic action we need. It will be -convenient to have a wrapper for this: - -``` -using ::testing::MakePolymorphicAction; -using ::testing::PolymorphicAction; - -PolymorphicAction ReturnSecondArgument() { - return MakePolymorphicAction(ReturnSecondArgumentAction()); -} -``` - -Now, you can use this polymorphic action the same way you use the -built-in ones: - -``` -using ::testing::_; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, int(bool flag, int n)); - MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(ReturnSecondArgument()); - EXPECT_CALL(foo, DoThat(_, _, _)) - .WillOnce(ReturnSecondArgument()); - ... - foo.DoThis(true, 5); // Will return 5. - foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". -``` - -## Teaching Google Mock How to Print Your Values ## - -When an uninteresting or unexpected call occurs, Google Mock prints -the argument values to help you debug. The `EXPECT_THAT` and -`ASSERT_THAT` assertions also print the value being validated when the -test fails. Google Mock does this using the user-extensible value -printer defined in ``. - -This printer knows how to print the built-in C++ types, native arrays, -STL containers, and any type that supports the `<<` operator. For -other types, it prints the raw bytes in the value and hope you the -user can figure it out. - -Did I say that the printer is `extensible`? That means you can teach -it to do a better job at printing your particular type than to dump -the bytes. To do that, you just need to define `<<` for your type: - -``` -#include - -namespace foo { - -class Foo { ... }; - -// It's important that the << operator is defined in the SAME -// namespace that defines Foo. C++'s look-up rules rely on that. -::std::ostream& operator<<(::std::ostream& os, const Foo& foo) { - return os << foo.DebugString(); // Whatever needed to print foo to os. -} - -} // namespace foo -``` - -Sometimes, this might not be an option. For example, your team may -consider it dangerous or bad style to have a `<<` operator for `Foo`, -or `Foo` may already have a `<<` operator that doesn't do what you -want (and you cannot change it). Don't despair though - Google Mock -gives you a second chance to get it right. Namely, you can define a -`PrintTo()` function like this: - -``` -#include - -namespace foo { - -class Foo { ... }; - -// It's important that PrintTo() is defined in the SAME -// namespace that defines Foo. C++'s look-up rules rely on that. -void PrintTo(const Foo& foo, ::std::ostream* os) { - *os << foo.DebugString(); // Whatever needed to print foo to os. -} - -} // namespace foo -``` - -What if you have both `<<` and `PrintTo()`? In this case, the latter -will override the former when Google Mock is concerned. This allows -you to customize how the value should appear in Google Mock's output -without affecting code that relies on the behavior of its `<<` -operator. - -**Note:** When printing a pointer of type `T*`, Google Mock calls -`PrintTo(T*, std::ostream* os)` instead of `operator<<(std::ostream&, T*)`. -Therefore the only way to affect how a pointer is printed by Google -Mock is to define `PrintTo()` for it. Also note that `T*` and `const T*` -are different types, so you may need to define `PrintTo()` for both. - -Why does Google Mock treat pointers specially? There are several reasons: - - * We cannot use `operator<<` to print a `signed char*` or `unsigned char*`, since it will print the pointer as a NUL-terminated C string, which likely will cause an access violation. - * We want `NULL` pointers to be printed as `"NULL"`, but `operator<<` prints it as `"0"`, `"nullptr"`, or something else, depending on the compiler. - * With some compilers, printing a `NULL` `char*` using `operator<<` will segfault. - * `operator<<` prints a function pointer as a `bool` (hence it always prints `"1"`), which is not very useful. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_5/Documentation.md b/src/libtoast/gtest/googlemock/docs/v1_5/Documentation.md deleted file mode 100644 index 315b0a298..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_5/Documentation.md +++ /dev/null @@ -1,11 +0,0 @@ -This page lists all documentation wiki pages for Google Mock **version 1.5.0** -- **if you use a different version of Google Mock, please read the documentation for that specific version instead.** - - * [ForDummies](V1_5_ForDummies.md) -- start here if you are new to Google Mock. - * [CheatSheet](V1_5_CheatSheet.md) -- a quick reference. - * [CookBook](V1_5_CookBook.md) -- recipes for doing various tasks using Google Mock. - * [FrequentlyAskedQuestions](V1_5_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. - -To contribute code to Google Mock, read: - - * DevGuide -- read this _before_ writing your first patch. - * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_5/ForDummies.md b/src/libtoast/gtest/googlemock/docs/v1_5/ForDummies.md deleted file mode 100644 index fcc3b5617..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_5/ForDummies.md +++ /dev/null @@ -1,439 +0,0 @@ - - -(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](V1_5_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md).) - -# What Is Google C++ Mocking Framework? # -When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). - -**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: - - * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. - * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. - -If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. - -**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. - -Using Google Mock involves three basic steps: - - 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; - 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; - 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. - -# Why Google Mock? # -While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: - - * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. - * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. - * The knowledge you gained from using one mock doesn't transfer to the next. - -In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. - -Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: - - * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". - * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). - * Your tests are brittle as some resources they use are unreliable (e.g. the network). - * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. - * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. - * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. - -We encourage you to use Google Mock as: - - * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! - * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. - -# Getting Started # -Using Google Mock is easy! Inside your C++ source file, just `#include` `` and ``, and you are ready to go. - -# A Case for Mock Turtles # -Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: - -``` -class Turtle { - ... - virtual ~Turtle() {} - virtual void PenUp() = 0; - virtual void PenDown() = 0; - virtual void Forward(int distance) = 0; - virtual void Turn(int degrees) = 0; - virtual void GoTo(int x, int y) = 0; - virtual int GetX() const = 0; - virtual int GetY() const = 0; -}; -``` - -(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) - -You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. - -Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. - -# Writing the Mock Class # -If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) - -## How to Define It ## -Using the `Turtle` interface as example, here are the simple steps you need to follow: - - 1. Derive a class `MockTurtle` from `Turtle`. - 1. Take a virtual function of `Turtle`. Count how many arguments it has. - 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. - 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). - 1. Repeat until all virtual functions you want to mock are done. - -After the process, you should have something like: - -``` -#include // Brings in Google Mock. -class MockTurtle : public Turtle { - public: - ... - MOCK_METHOD0(PenUp, void()); - MOCK_METHOD0(PenDown, void()); - MOCK_METHOD1(Forward, void(int distance)); - MOCK_METHOD1(Turn, void(int degrees)); - MOCK_METHOD2(GoTo, void(int x, int y)); - MOCK_CONST_METHOD0(GetX, int()); - MOCK_CONST_METHOD0(GetY, int()); -}; -``` - -You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. - -**Tip:** If even this is too much work for you, you'll find the -`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line -tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, -and it will print the definition of the mock class for you. Due to the -complexity of the C++ language, this script may not always work, but -it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). - -## Where to Put It ## -When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) - -So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. - -Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. - -# Using Mocks in Tests # -Once you have a mock class, using it is easy. The typical work flow is: - - 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). - 1. Create some mock objects. - 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). - 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. - 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. - -Here's an example: - -``` -#include "path/to/mock-turtle.h" -#include -#include -using ::testing::AtLeast; // #1 - -TEST(PainterTest, CanDrawSomething) { - MockTurtle turtle; // #2 - EXPECT_CALL(turtle, PenDown()) // #3 - .Times(AtLeast(1)); - - Painter painter(&turtle); // #4 - - EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); -} // #5 - -int main(int argc, char** argv) { - // The following line must be executed to initialize Google Mock - // (and Google Test) before running the tests. - ::testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: - -``` -path/to/my_test.cc:119: Failure -Actual function call count doesn't match this expectation: -Actually: never called; -Expected: called at least once. -``` - -**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. - -**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. - -**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. - -This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. - -Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. - -## Using Google Mock with Any Testing Framework ## -If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or -[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: -``` -int main(int argc, char** argv) { - // The following line causes Google Mock to throw an exception on failure, - // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = true; - ::testing::InitGoogleMock(&argc, argv); - ... whatever your testing framework requires ... -} -``` - -This approach has a catch: it makes Google Mock throw an exception -from a mock object's destructor sometimes. With some compilers, this -sometimes causes the test program to crash. You'll still be able to -notice that the test has failed, but it's not a graceful failure. - -A better solution is to use Google Test's -[event listener API](http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) -to report a test failure to your testing framework properly. You'll need to -implement the `OnTestPartResult()` method of the event listener interface, but it -should be straightforward. - -If this turns out to be too much work, we suggest that you stick with -Google Test, which works with Google Mock seamlessly (in fact, it is -technically part of Google Mock.). If there is a reason that you -cannot use Google Test, please let us know. - -# Setting Expectations # -The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." - -## General Syntax ## -In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: - -``` -EXPECT_CALL(mock_object, method(matchers)) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) - -The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. - -This syntax is designed to make an expectation read like English. For example, you can probably guess that - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .Times(5) - .WillOnce(Return(100)) - .WillOnce(Return(150)) - .WillRepeatedly(Return(200)); -``` - -says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). - -**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. - -## Matchers: What Arguments Do We Expect? ## -When a mock function takes arguments, we must specify what arguments we are expecting; for example: - -``` -// Expects the turtle to move forward by 100 units. -EXPECT_CALL(turtle, Forward(100)); -``` - -Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": - -``` -using ::testing::_; -... -// Expects the turtle to move forward. -EXPECT_CALL(turtle, Forward(_)); -``` - -`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. - -A list of built-in matchers can be found in the [CheatSheet](V1_5_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: - -``` -using ::testing::Ge;... -EXPECT_CALL(turtle, Forward(Ge(100))); -``` - -This checks that the turtle will be told to go forward by at least 100 units. - -## Cardinalities: How Many Times Will It Be Called? ## -The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. - -An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. - -We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_5_CheatSheet.md). - -The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: - - * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. - * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. - * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. - -**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? - -## Actions: What Should It Do? ## -Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. - -First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. - -Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillOnce(Return(300)); -``` - -This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillRepeatedly(Return(300)); -``` - -says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. - -Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). - -What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](V1_5_CheatSheet#Actions.md). - -**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: - -``` -int n = 100; -EXPECT_CALL(turtle, GetX()) -.Times(4) -.WillOnce(Return(n++)); -``` - -Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_5_CookBook.md). - -Time for another quiz! What do you think the following means? - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) -.Times(4) -.WillOnce(Return(100)); -``` - -Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. - -## Using Multiple Expectations ## -So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. - -By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: - -``` -using ::testing::_;... -EXPECT_CALL(turtle, Forward(_)); // #1 -EXPECT_CALL(turtle, Forward(10)) // #2 - .Times(2); -``` - -If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. - -**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. - -## Ordered vs Unordered Calls ## -By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. - -Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: - -``` -using ::testing::InSequence;... -TEST(FooTest, DrawsLineSegment) { - ... - { - InSequence dummy; - - EXPECT_CALL(turtle, PenDown()); - EXPECT_CALL(turtle, Forward(100)); - EXPECT_CALL(turtle, PenUp()); - } - Foo(); -} -``` - -By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. - -In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. - -(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_5_CookBook.md).) - -## All Expectations Are Sticky (Unless Said Otherwise) ## -Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? - -After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): - -``` -using ::testing::_;... -EXPECT_CALL(turtle, GoTo(_, _)) // #1 - .Times(AnyNumber()); -EXPECT_CALL(turtle, GoTo(0, 0)) // #2 - .Times(2); -``` - -Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. - -This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). - -Simple? Let's see if you've really understood it: what does the following code say? - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)); -} -``` - -If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! - -One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); -} -``` - -And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: - -``` -using ::testing::InSequence; -using ::testing::Return; -... -{ - InSequence s; - - for (int i = 1; i <= n; i++) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); - } -} -``` - -By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). - -## Uninteresting Calls ## -A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. - -In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. - -# What Now? # -Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. - -Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_5_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_5/FrequentlyAskedQuestions.md b/src/libtoast/gtest/googlemock/docs/v1_5/FrequentlyAskedQuestions.md deleted file mode 100644 index 7593243c3..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_5/FrequentlyAskedQuestions.md +++ /dev/null @@ -1,624 +0,0 @@ - - -Please send your questions to the -[googlemock](http://groups.google.com/group/googlemock) discussion -group. If you need help with compiler errors, make sure you have -tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. - -## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## - -After version 1.4.0 of Google Mock was released, we had an idea on how -to make it easier to write matchers that can generate informative -messages efficiently. We experimented with this idea and liked what -we saw. Therefore we decided to implement it. - -Unfortunately, this means that if you have defined your own matchers -by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, -your definitions will no longer compile. Matchers defined using the -`MATCHER*` family of macros are not affected. - -Sorry for the hassle if your matchers are affected. We believe it's -in everyone's long-term interest to make this change sooner than -later. Fortunately, it's usually not hard to migrate an existing -matcher to the new API. Here's what you need to do: - -If you wrote your matcher like this: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` - -you'll need to change it to: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` -(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second -argument of type `MatchResultListener*`.) - -If you were also using `ExplainMatchResultTo()` to improve the matcher -message: -``` -// Old matcher definition that doesn't work with the lastest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - - virtual void ExplainMatchResultTo(MyType value, - ::std::ostream* os) const { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Foo property is " << value.GetFoo(); - } - ... -}; -``` - -you should move the logic of `ExplainMatchResultTo()` into -`MatchAndExplain()`, using the `MatchResultListener` argument where -the `::std::ostream` was used: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Foo property is " << value.GetFoo(); - return value.GetFoo() > 5; - } - ... -}; -``` - -If your matcher is defined using `MakePolymorphicMatcher()`: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you should rename the `Matches()` method to `MatchAndExplain()` and -add a `MatchResultListener*` argument (the same as what you need to do -for matchers defined by implementing `MatcherInterface`): -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -If your polymorphic matcher uses `ExplainMatchResultTo()` for better -failure messages: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -void ExplainMatchResultTo(const MyGreatMatcher& matcher, - MyType value, - ::std::ostream* os) { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Bar property is " << value.GetBar(); -} -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you'll need to move the logic inside `ExplainMatchResultTo()` to -`MatchAndExplain()`: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Bar property is " << value.GetBar(); - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -For more information, you can read these -[two](V1_5_CookBook#Writing_New_Monomorphic_Matchers.md) -[recipes](V1_5_CookBook#Writing_New_Polymorphic_Matchers.md) -from the cookbook. As always, you -are welcome to post questions on `googlemock@googlegroups.com` if you -need any help. - -## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## - -Google Mock works out of the box with Google Test. However, it's easy -to configure it to work with any testing framework of your choice. -[Here](V1_5_ForDummies#Using_Google_Mock_with_Any_Testing_Framework.md) is how. - -## How am I supposed to make sense of these horrible template errors? ## - -If you are confused by the compiler errors gcc threw at you, -try consulting the _Google Mock Doctor_ tool first. What it does is to -scan stdin for gcc error messages, and spit out diagnoses on the -problems (we call them diseases) your code has. - -To "install", run command: -``` -alias gmd='/scripts/gmock_doctor.py' -``` - -To use it, do: -``` - 2>&1 | gmd -``` - -For example: -``` -make my_test 2>&1 | gmd -``` - -Or you can run `gmd` and copy-n-paste gcc's error messages to it. - -## Can I mock a variadic function? ## - -You cannot mock a variadic function (i.e. a function taking ellipsis -(`...`) arguments) directly in Google Mock. - -The problem is that in general, there is _no way_ for a mock object to -know how many arguments are passed to the variadic method, and what -the arguments' types are. Only the _author of the base class_ knows -the protocol, and we cannot look into his head. - -Therefore, to mock such a function, the _user_ must teach the mock -object how to figure out the number of arguments and their types. One -way to do it is to provide overloaded versions of the function. - -Ellipsis arguments are inherited from C and not really a C++ feature. -They are unsafe to use and don't work with arguments that have -constructors or destructors. Therefore we recommend to avoid them in -C++ as much as possible. - -## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## - -If you compile this using Microsoft Visual C++ 2005 SP1: -``` -class Foo { - ... - virtual void Bar(const int i) = 0; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Bar, void(const int i)); -}; -``` -You may get the following warning: -``` -warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier -``` - -This is a MSVC bug. The same code compiles fine with gcc ,for -example. If you use Visual C++ 2008 SP1, you would get the warning: -``` -warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers -``` - -In C++, if you _declare_ a function with a `const` parameter, the -`const` modifier is _ignored_. Therefore, the `Foo` base class above -is equivalent to: -``` -class Foo { - ... - virtual void Bar(int i) = 0; // int or const int? Makes no difference. -}; -``` - -In fact, you can _declare_ Bar() with an `int` parameter, and _define_ -it with a `const int` parameter. The compiler will still match them -up. - -Since making a parameter `const` is meaningless in the method -_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. -That should workaround the VC bug. - -Note that we are talking about the _top-level_ `const` modifier here. -If the function parameter is passed by pointer or reference, declaring -the _pointee_ or _referee_ as `const` is still meaningful. For -example, the following two declarations are _not_ equivalent: -``` -void Bar(int* p); // Neither p nor *p is const. -void Bar(const int* p); // p is not const, but *p is. -``` - -## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## - -We've noticed that when the `/clr` compiler flag is used, Visual C++ -uses 5~6 times as much memory when compiling a mock class. We suggest -to avoid `/clr` when compiling native C++ mocks. - -## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## - -You might want to run your test with -`--gmock_verbose=info`. This flag lets Google Mock print a trace -of every mock function call it receives. By studying the trace, -you'll gain insights on why the expectations you set are not met. - -## How can I assert that a function is NEVER called? ## - -``` -EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## - -When Google Mock detects a failure, it prints relevant information -(the mock function arguments, the state of relevant expectations, and -etc) to help the user debug. If another failure is detected, Google -Mock will do the same, including printing the state of relevant -expectations. - -Sometimes an expectation's state didn't change between two failures, -and you'll see the same description of the state twice. They are -however _not_ redundant, as they refer to _different points in time_. -The fact they are the same _is_ interesting information. - -## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## - -Does the class (hopefully a pure interface) you are mocking have a -virtual destructor? - -Whenever you derive from a base class, make sure its destructor is -virtual. Otherwise Bad Things will happen. Consider the following -code: - -``` -class Base { - public: - // Not virtual, but should be. - ~Base() { ... } - ... -}; - -class Derived : public Base { - public: - ... - private: - std::string value_; -}; - -... - Base* p = new Derived; - ... - delete p; // Surprise! ~Base() will be called, but ~Derived() will not - // - value_ is leaked. -``` - -By changing `~Base()` to virtual, `~Derived()` will be correctly -called when `delete p` is executed, and the heap checker -will be happy. - -## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## - -When people complain about this, often they are referring to code like: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. However, I have to write the expectations in the -// reverse order. This sucks big time!!! -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); -``` - -The problem is that they didn't pick the **best** way to express the test's -intent. - -By default, expectations don't have to be matched in _any_ particular -order. If you want them to match in a certain order, you need to be -explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's -easy to accidentally over-specify your tests, and we want to make it -harder to do so. - -There are two better ways to write the test spec. You could either -put the expectations in sequence: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. Using a sequence, we can write the expectations -// in their natural order. -{ - InSequence s; - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -} -``` - -or you can put the sequence of actions in the same expectation: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -``` - -Back to the original questions: why does Google Mock search the -expectations (and `ON_CALL`s) from back to front? Because this -allows a user to set up a mock's behavior for the common case early -(e.g. in the mock's constructor or the test fixture's set-up phase) -and customize it with more specific rules later. If Google Mock -searches from front to back, this very useful pattern won't be -possible. - -## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## - -When choosing between being neat and being safe, we lean toward the -latter. So the answer is that we think it's better to show the -warning. - -Often people write `ON_CALL`s in the mock object's -constructor or `SetUp()`, as the default behavior rarely changes from -test to test. Then in the test body they set the expectations, which -are often different for each test. Having an `ON_CALL` in the set-up -part of a test doesn't mean that the calls are expected. If there's -no `EXPECT_CALL` and the method is called, it's possibly an error. If -we quietly let the call go through without notifying the user, bugs -may creep in unnoticed. - -If, however, you are sure that the calls are OK, you can write - -``` -EXPECT_CALL(foo, Bar(_)) - .WillRepeatedly(...); -``` - -instead of - -``` -ON_CALL(foo, Bar(_)) - .WillByDefault(...); -``` - -This tells Google Mock that you do expect the calls and no warning should be -printed. - -Also, you can control the verbosity using the `--gmock_verbose` flag. -If you find the output too noisy when debugging, just choose a less -verbose level. - -## How can I delete the mock function's argument in an action? ## - -If you find yourself needing to perform some action that's not -supported by Google Mock directly, remember that you can define your own -actions using -[MakeAction()](V1_5_CookBook#Writing_New_Actions.md) or -[MakePolymorphicAction()](V1_5_CookBook#Writing_New_Polymorphic_Actions.md), -or you can write a stub function and invoke it using -[Invoke()](V1_5_CookBook#Using_Functions_Methods_Functors.md). - -## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## - -What?! I think it's beautiful. :-) - -While which syntax looks more natural is a subjective matter to some -extent, Google Mock's syntax was chosen for several practical advantages it -has. - -Try to mock a function that takes a map as an argument: -``` -virtual int GetSize(const map& m); -``` - -Using the proposed syntax, it would be: -``` -MOCK_METHOD1(GetSize, int, const map& m); -``` - -Guess what? You'll get a compiler error as the compiler thinks that -`const map& m` are **two**, not one, arguments. To work -around this you can use `typedef` to give the map type a name, but -that gets in the way of your work. Google Mock's syntax avoids this -problem as the function's argument types are protected inside a pair -of parentheses: -``` -// This compiles fine. -MOCK_METHOD1(GetSize, int(const map& m)); -``` - -You still need a `typedef` if the return type contains an unprotected -comma, but that's much rarer. - -Other advantages include: - 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. - 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. - 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! - -## My code calls a static/global function. Can I mock it? ## - -You can, but you need to make some changes. - -In general, if you find yourself needing to mock a static function, -it's a sign that your modules are too tightly coupled (and less -flexible, less reusable, less testable, etc). You are probably better -off defining a small interface and call the function through that -interface, which then can be easily mocked. It's a bit of work -initially, but usually pays for itself quickly. - -This Google Testing Blog -[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) -says it excellently. Check it out. - -## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## - -I know it's not a question, but you get an answer for free any way. :-) - -With Google Mock, you can create mocks in C++ easily. And people might be -tempted to use them everywhere. Sometimes they work great, and -sometimes you may find them, well, a pain to use. So, what's wrong in -the latter case? - -When you write a test without using mocks, you exercise the code and -assert that it returns the correct value or that the system is in an -expected state. This is sometimes called "state-based testing". - -Mocks are great for what some call "interaction-based" testing: -instead of checking the system state at the very end, mock objects -verify that they are invoked the right way and report an error as soon -as it arises, giving you a handle on the precise context in which the -error was triggered. This is often more effective and economical to -do than state-based testing. - -If you are doing state-based testing and using a test double just to -simulate the real object, you are probably better off using a fake. -Using a mock in this case causes pain, as it's not a strong point for -mocks to perform complex actions. If you experience this and think -that mocks suck, you are just not using the right tool for your -problem. Or, you might be trying to solve the wrong problem. :-) - -## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## - -By all means, NO! It's just an FYI. - -What it means is that you have a mock function, you haven't set any -expectations on it (by Google Mock's rule this means that you are not -interested in calls to this function and therefore it can be called -any number of times), and it is called. That's OK - you didn't say -it's not OK to call the function! - -What if you actually meant to disallow this function to be called, but -forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While -one can argue that it's the user's fault, Google Mock tries to be nice and -prints you a note. - -So, when you see the message and believe that there shouldn't be any -uninteresting calls, you should investigate what's going on. To make -your life easier, Google Mock prints the function name and arguments -when an uninteresting call is encountered. - -## I want to define a custom action. Should I use Invoke() or implement the action interface? ## - -Either way is fine - you want to choose the one that's more convenient -for your circumstance. - -Usually, if your action is for a particular function type, defining it -using `Invoke()` should be easier; if your action can be used in -functions of different types (e.g. if you are defining -`Return(value)`), `MakePolymorphicAction()` is -easiest. Sometimes you want precise control on what types of -functions the action can be used in, and implementing -`ActionInterface` is the way to go here. See the implementation of -`Return()` in `include/gmock/gmock-actions.h` for an example. - -## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## - -You got this error as Google Mock has no idea what value it should return -when the mock method is called. `SetArgumentPointee()` says what the -side effect is, but doesn't say what the return value should be. You -need `DoAll()` to chain a `SetArgumentPointee()` with a `Return()`. - -See this [recipe](V1_5_CookBook#Mocking_Side_Effects.md) for more details and an example. - - -## My question is not in your FAQ! ## - -If you cannot find the answer to your question in this FAQ, there are -some other resources you can use: - - 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), - 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), - 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). - -Please note that creating an issue in the -[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ -a good way to get your answer, as it is monitored infrequently by a -very small number of people. - -When asking a question, it's helpful to provide as much of the -following information as possible (people cannot help you if there's -not enough information in your question): - - * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), - * your operating system, - * the name and version of your compiler, - * the complete command line flags you give to your compiler, - * the complete compiler error messages (if the question is about compilation), - * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_6/CheatSheet.md b/src/libtoast/gtest/googlemock/docs/v1_6/CheatSheet.md deleted file mode 100644 index 91de1d210..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_6/CheatSheet.md +++ /dev/null @@ -1,534 +0,0 @@ - - -# Defining a Mock Class # - -## Mocking a Normal Class ## - -Given -``` -class Foo { - ... - virtual ~Foo(); - virtual int GetSize() const = 0; - virtual string Describe(const char* name) = 0; - virtual string Describe(int type) = 0; - virtual bool Process(Bar elem, int count) = 0; -}; -``` -(note that `~Foo()` **must** be virtual) we can define its mock as -``` -#include "gmock/gmock.h" - -class MockFoo : public Foo { - MOCK_CONST_METHOD0(GetSize, int()); - MOCK_METHOD1(Describe, string(const char* name)); - MOCK_METHOD1(Describe, string(int type)); - MOCK_METHOD2(Process, bool(Bar elem, int count)); -}; -``` - -To create a "nice" mock object which ignores all uninteresting calls, -or a "strict" mock object, which treats them as failures: -``` -NiceMock nice_foo; // The type is a subclass of MockFoo. -StrictMock strict_foo; // The type is a subclass of MockFoo. -``` - -## Mocking a Class Template ## - -To mock -``` -template -class StackInterface { - public: - ... - virtual ~StackInterface(); - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; -``` -(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: -``` -template -class MockStack : public StackInterface { - public: - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Specifying Calling Conventions for Mock Functions ## - -If your mock function doesn't use the default calling convention, you -can specify it by appending `_WITH_CALLTYPE` to any of the macros -described in the previous two sections and supplying the calling -convention as the first argument to the macro. For example, -``` - MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); - MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); -``` -where `STDMETHODCALLTYPE` is defined by `` on Windows. - -# Using Mocks in Tests # - -The typical flow is: - 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. - 1. Create the mock objects. - 1. Optionally, set the default actions of the mock objects. - 1. Set your expectations on the mock objects (How will they be called? What wil they do?). - 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. - 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. - -Here is an example: -``` -using ::testing::Return; // #1 - -TEST(BarTest, DoesThis) { - MockFoo foo; // #2 - - ON_CALL(foo, GetSize()) // #3 - .WillByDefault(Return(1)); - // ... other default actions ... - - EXPECT_CALL(foo, Describe(5)) // #4 - .Times(3) - .WillRepeatedly(Return("Category 5")); - // ... other expectations ... - - EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 -} // #6 -``` - -# Setting Default Actions # - -Google Mock has a **built-in default action** for any function that -returns `void`, `bool`, a numeric value, or a pointer. - -To customize the default action for functions with return type `T` globally: -``` -using ::testing::DefaultValue; - -DefaultValue::Set(value); // Sets the default value to be returned. -// ... use the mocks ... -DefaultValue::Clear(); // Resets the default value. -``` - -To customize the default action for a particular method, use `ON_CALL()`: -``` -ON_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .WillByDefault(action); -``` - -# Setting Expectations # - -`EXPECT_CALL()` sets **expectations** on a mock method (How will it be -called? What will it do?): -``` -EXPECT_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .Times(cardinality) ? - .InSequence(sequences) * - .After(expectations) * - .WillOnce(action) * - .WillRepeatedly(action) ? - .RetiresOnSaturation(); ? -``` - -If `Times()` is omitted, the cardinality is assumed to be: - - * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; - * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or - * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. - -A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. - -# Matchers # - -A **matcher** matches a _single_ argument. You can use it inside -`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value -directly: - -| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | -|:------------------------------|:----------------------------------------| -| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | - -Built-in matchers (where `argument` is the function argument) are -divided into several categories: - -## Wildcard ## -|`_`|`argument` can be any value of the correct type.| -|:--|:-----------------------------------------------| -|`A()` or `An()`|`argument` can be any value of type `type`. | - -## Generic Comparison ## - -|`Eq(value)` or `value`|`argument == value`| -|:---------------------|:------------------| -|`Ge(value)` |`argument >= value`| -|`Gt(value)` |`argument > value` | -|`Le(value)` |`argument <= value`| -|`Lt(value)` |`argument < value` | -|`Ne(value)` |`argument != value`| -|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| -|`NotNull()` |`argument` is a non-null pointer (raw or smart).| -|`Ref(variable)` |`argument` is a reference to `variable`.| -|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| - -Except `Ref()`, these matchers make a _copy_ of `value` in case it's -modified or destructed later. If the compiler complains that `value` -doesn't have a public copy constructor, try wrap it in `ByRef()`, -e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure -`non_copyable_value` is not changed afterwards, or the meaning of your -matcher will be changed. - -## Floating-Point Matchers ## - -|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| -|:-------------------|:----------------------------------------------------------------------------------------------| -|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | -|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | -|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | - -These matchers use ULP-based comparison (the same as used in -[Google Test](http://code.google.com/p/googletest/)). They -automatically pick a reasonable error bound based on the absolute -value of the expected value. `DoubleEq()` and `FloatEq()` conform to -the IEEE standard, which requires comparing two NaNs for equality to -return false. The `NanSensitive*` version instead treats two NaNs as -equal, which is often what a user wants. - -## String Matchers ## - -The `argument` can be either a C string or a C++ string object: - -|`ContainsRegex(string)`|`argument` matches the given regular expression.| -|:----------------------|:-----------------------------------------------| -|`EndsWith(suffix)` |`argument` ends with string `suffix`. | -|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | -|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| -|`StartsWith(prefix)` |`argument` starts with string `prefix`. | -|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | -|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| -|`StrEq(string)` |`argument` is equal to `string`. | -|`StrNe(string)` |`argument` is not equal to `string`. | - -`ContainsRegex()` and `MatchesRegex()` use the regular expression -syntax defined -[here](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Regular_Expression_Syntax). -`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide -strings as well. - -## Container Matchers ## - -Most STL-style containers support `==`, so you can use -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. If you want to write the elements in-line, -match them more flexibly, or get more informative messages, you can use: - -| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | -|:--------------|:-------------------------------------------------------------------------------------------| -| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | -| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | -| `ElementsAreArray(array)` or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array. | -| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | -| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. | - -These matchers can also match: - - 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and - 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). - -where the array may be multi-dimensional (i.e. its elements can be arrays). - -## Member Matchers ## - -|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| -|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| -|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| -|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | -|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| - -## Matching the Result of a Function or Functor ## - -|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| -|:---------------|:---------------------------------------------------------------------| - -## Pointer Matchers ## - -|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| -|:-----------|:-----------------------------------------------------------------------------------------------| - -## Multiargument Matchers ## - -Technically, all matchers match a _single_ value. A "multi-argument" -matcher is just one that matches a _tuple_. The following matchers can -be used to match a tuple `(x, y)`: - -|`Eq()`|`x == y`| -|:-----|:-------| -|`Ge()`|`x >= y`| -|`Gt()`|`x > y` | -|`Le()`|`x <= y`| -|`Lt()`|`x < y` | -|`Ne()`|`x != y`| - -You can use the following selectors to pick a subset of the arguments -(or reorder them) to participate in the matching: - -|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| -|:-----------|:-------------------------------------------------------------------| -|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| - -## Composite Matchers ## - -You can make a matcher from one or more other matchers: - -|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| -|:-----------------------|:---------------------------------------------------| -|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| -|`Not(m)` |`argument` doesn't match matcher `m`. | - -## Adapters for Matchers ## - -|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| -|:------------------|:--------------------------------------| -|`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | -|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| - -## Matchers as Predicates ## - -|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| -|:------------------|:---------------------------------------------------------------------------------------------| -|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | -|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | - -## Defining Matchers ## - -| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | -|:-------------------------------------------------|:------------------------------------------------------| -| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | - -**Notes:** - - 1. The `MATCHER*` macros cannot be used inside a function or class. - 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). - 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. - -## Matchers as Test Assertions ## - -|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/V1_6_Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| -|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| -|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | - -# Actions # - -**Actions** specify what a mock function should do when invoked. - -## Returning a Value ## - -|`Return()`|Return from a `void` mock function.| -|:---------|:----------------------------------| -|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| -|`ReturnArg()`|Return the `N`-th (0-based) argument.| -|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| -|`ReturnNull()`|Return a null pointer. | -|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| -|`ReturnRef(variable)`|Return a reference to `variable`. | -|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| - -## Side Effects ## - -|`Assign(&variable, value)`|Assign `value` to variable.| -|:-------------------------|:--------------------------| -| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | -| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | -| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | -|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| -|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| -|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| -|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| -|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| - -## Using a Function or a Functor as an Action ## - -|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| -|:----------|:-----------------------------------------------------------------------------------------------------------------| -|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | -|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | -|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | -|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| - -The return value of the invoked function is used as the return value -of the action. - -When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: -``` - double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } - ... - EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); -``` - -In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, -``` - InvokeArgument<2>(5, string("Hi"), ByRef(foo)) -``` -calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. - -## Default Action ## - -|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| -|:------------|:--------------------------------------------------------------------| - -**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. - -## Composite Actions ## - -|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | -|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| -|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | -|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | -|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | -|`WithoutArgs(a)` |Perform action `a` without any arguments. | - -## Defining Actions ## - -| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | -|:--------------------------------------|:---------------------------------------------------------------------------------------| -| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | -| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | - -The `ACTION*` macros cannot be used inside a function or class. - -# Cardinalities # - -These are used in `Times()` to specify how many times a mock function will be called: - -|`AnyNumber()`|The function can be called any number of times.| -|:------------|:----------------------------------------------| -|`AtLeast(n)` |The call is expected at least `n` times. | -|`AtMost(n)` |The call is expected at most `n` times. | -|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| -|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| - -# Expectation Order # - -By default, the expectations can be matched in _any_ order. If some -or all expectations must be matched in a given order, there are two -ways to specify it. They can be used either independently or -together. - -## The After Clause ## - -``` -using ::testing::Expectation; -... -Expectation init_x = EXPECT_CALL(foo, InitX()); -Expectation init_y = EXPECT_CALL(foo, InitY()); -EXPECT_CALL(foo, Bar()) - .After(init_x, init_y); -``` -says that `Bar()` can be called only after both `InitX()` and -`InitY()` have been called. - -If you don't know how many pre-requisites an expectation has when you -write it, you can use an `ExpectationSet` to collect them: - -``` -using ::testing::ExpectationSet; -... -ExpectationSet all_inits; -for (int i = 0; i < element_count; i++) { - all_inits += EXPECT_CALL(foo, InitElement(i)); -} -EXPECT_CALL(foo, Bar()) - .After(all_inits); -``` -says that `Bar()` can be called only after all elements have been -initialized (but we don't care about which elements get initialized -before the others). - -Modifying an `ExpectationSet` after using it in an `.After()` doesn't -affect the meaning of the `.After()`. - -## Sequences ## - -When you have a long chain of sequential expectations, it's easier to -specify the order using **sequences**, which don't require you to given -each expectation in the chain a different name. All expected
-calls
in the same sequence must occur in the order they are -specified. - -``` -using ::testing::Sequence; -Sequence s1, s2; -... -EXPECT_CALL(foo, Reset()) - .InSequence(s1, s2) - .WillOnce(Return(true)); -EXPECT_CALL(foo, GetSize()) - .InSequence(s1) - .WillOnce(Return(1)); -EXPECT_CALL(foo, Describe(A())) - .InSequence(s2) - .WillOnce(Return("dummy")); -``` -says that `Reset()` must be called before _both_ `GetSize()` _and_ -`Describe()`, and the latter two can occur in any order. - -To put many expectations in a sequence conveniently: -``` -using ::testing::InSequence; -{ - InSequence dummy; - - EXPECT_CALL(...)...; - EXPECT_CALL(...)...; - ... - EXPECT_CALL(...)...; -} -``` -says that all expected calls in the scope of `dummy` must occur in -strict order. The name `dummy` is irrelevant.) - -# Verifying and Resetting a Mock # - -Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: -``` -using ::testing::Mock; -... -// Verifies and removes the expectations on mock_obj; -// returns true iff successful. -Mock::VerifyAndClearExpectations(&mock_obj); -... -// Verifies and removes the expectations on mock_obj; -// also removes the default actions set by ON_CALL(); -// returns true iff successful. -Mock::VerifyAndClear(&mock_obj); -``` - -You can also tell Google Mock that a mock object can be leaked and doesn't -need to be verified: -``` -Mock::AllowLeak(&mock_obj); -``` - -# Mock Classes # - -Google Mock defines a convenient mock class template -``` -class MockFunction { - public: - MOCK_METHODn(Call, R(A1, ..., An)); -}; -``` -See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Check_Points) for one application of it. - -# Flags # - -| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | -|:-------------------------------|:----------------------------------------------| -| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_6/CookBook.md b/src/libtoast/gtest/googlemock/docs/v1_6/CookBook.md deleted file mode 100644 index f5975a003..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_6/CookBook.md +++ /dev/null @@ -1,3342 +0,0 @@ - - -You can find recipes for using Google Mock here. If you haven't yet, -please read the [ForDummies](V1_6_ForDummies.md) document first to make sure you understand -the basics. - -**Note:** Google Mock lives in the `testing` name space. For -readability, it is recommended to write `using ::testing::Foo;` once in -your file before using the name `Foo` defined by Google Mock. We omit -such `using` statements in this page for brevity, but you should do it -in your own code. - -# Creating Mock Classes # - -## Mocking Private or Protected Methods ## - -You must always put a mock method definition (`MOCK_METHOD*`) in a -`public:` section of the mock class, regardless of the method being -mocked being `public`, `protected`, or `private` in the base class. -This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function -from outside of the mock class. (Yes, C++ allows a subclass to change -the access level of a virtual function in the base class.) Example: - -``` -class Foo { - public: - ... - virtual bool Transform(Gadget* g) = 0; - - protected: - virtual void Resume(); - - private: - virtual int GetTimeOut(); -}; - -class MockFoo : public Foo { - public: - ... - MOCK_METHOD1(Transform, bool(Gadget* g)); - - // The following must be in the public section, even though the - // methods are protected or private in the base class. - MOCK_METHOD0(Resume, void()); - MOCK_METHOD0(GetTimeOut, int()); -}; -``` - -## Mocking Overloaded Methods ## - -You can mock overloaded functions as usual. No special attention is required: - -``` -class Foo { - ... - - // Must be virtual as we'll inherit from Foo. - virtual ~Foo(); - - // Overloaded on the types and/or numbers of arguments. - virtual int Add(Element x); - virtual int Add(int times, Element x); - - // Overloaded on the const-ness of this object. - virtual Bar& GetBar(); - virtual const Bar& GetBar() const; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Add, int(Element x)); - MOCK_METHOD2(Add, int(int times, Element x); - - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -``` - -**Note:** if you don't mock all versions of the overloaded method, the -compiler will give you a warning about some methods in the base class -being hidden. To fix that, use `using` to bring them in scope: - -``` -class MockFoo : public Foo { - ... - using Foo::Add; - MOCK_METHOD1(Add, int(Element x)); - // We don't want to mock int Add(int times, Element x); - ... -}; -``` - -## Mocking Class Templates ## - -To mock a class template, append `_T` to the `MOCK_*` macros: - -``` -template -class StackInterface { - ... - // Must be virtual as we'll inherit from StackInterface. - virtual ~StackInterface(); - - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; - -template -class MockStack : public StackInterface { - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Mocking Nonvirtual Methods ## - -Google Mock can mock non-virtual functions to be used in what we call _hi-perf -dependency injection_. - -In this case, instead of sharing a common base class with the real -class, your mock class will be _unrelated_ to the real class, but -contain methods with the same signatures. The syntax for mocking -non-virtual methods is the _same_ as mocking virtual methods: - -``` -// A simple packet stream class. None of its members is virtual. -class ConcretePacketStream { - public: - void AppendPacket(Packet* new_packet); - const Packet* GetPacket(size_t packet_number) const; - size_t NumberOfPackets() const; - ... -}; - -// A mock packet stream class. It inherits from no other, but defines -// GetPacket() and NumberOfPackets(). -class MockPacketStream { - public: - MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); - MOCK_CONST_METHOD0(NumberOfPackets, size_t()); - ... -}; -``` - -Note that the mock class doesn't define `AppendPacket()`, unlike the -real class. That's fine as long as the test doesn't need to call it. - -Next, you need a way to say that you want to use -`ConcretePacketStream` in production code, and use `MockPacketStream` -in tests. Since the functions are not virtual and the two classes are -unrelated, you must specify your choice at _compile time_ (as opposed -to run time). - -One way to do it is to templatize your code that needs to use a packet -stream. More specifically, you will give your code a template type -argument for the type of the packet stream. In production, you will -instantiate your template with `ConcretePacketStream` as the type -argument. In tests, you will instantiate the same template with -`MockPacketStream`. For example, you may write: - -``` -template -void CreateConnection(PacketStream* stream) { ... } - -template -class PacketReader { - public: - void ReadPackets(PacketStream* stream, size_t packet_num); -}; -``` - -Then you can use `CreateConnection()` and -`PacketReader` in production code, and use -`CreateConnection()` and -`PacketReader` in tests. - -``` - MockPacketStream mock_stream; - EXPECT_CALL(mock_stream, ...)...; - .. set more expectations on mock_stream ... - PacketReader reader(&mock_stream); - ... exercise reader ... -``` - -## Mocking Free Functions ## - -It's possible to use Google Mock to mock a free function (i.e. a -C-style function or a static method). You just need to rewrite your -code to use an interface (abstract class). - -Instead of calling a free function (say, `OpenFile`) directly, -introduce an interface for it and have a concrete subclass that calls -the free function: - -``` -class FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) = 0; -}; - -class File : public FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) { - return OpenFile(path, mode); - } -}; -``` - -Your code should talk to `FileInterface` to open a file. Now it's -easy to mock out the function. - -This may seem much hassle, but in practice you often have multiple -related functions that you can put in the same interface, so the -per-function syntactic overhead will be much lower. - -If you are concerned about the performance overhead incurred by -virtual functions, and profiling confirms your concern, you can -combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). - -## Nice Mocks and Strict Mocks ## - -If a mock method has no `EXPECT_CALL` spec but is called, Google Mock -will print a warning about the "uninteresting call". The rationale is: - - * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. - * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. - -However, sometimes you may want to suppress all "uninteresting call" -warnings, while sometimes you may want the opposite, i.e. to treat all -of them as errors. Google Mock lets you make the decision on a -per-mock-object basis. - -Suppose your test uses a mock class `MockFoo`: - -``` -TEST(...) { - MockFoo mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -If a method of `mock_foo` other than `DoThis()` is called, it will be -reported by Google Mock as a warning. However, if you rewrite your -test to use `NiceMock` instead, the warning will be gone, -resulting in a cleaner test output: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -`NiceMock` is a subclass of `MockFoo`, so it can be used -wherever `MockFoo` is accepted. - -It also works if `MockFoo`'s constructor takes some arguments, as -`NiceMock` "inherits" `MockFoo`'s constructors: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -The usage of `StrictMock` is similar, except that it makes all -uninteresting calls failures: - -``` -using ::testing::StrictMock; - -TEST(...) { - StrictMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... - - // The test will fail if a method of mock_foo other than DoThis() - // is called. -} -``` - -There are some caveats though (I don't like them just as much as the -next guy, but sadly they are side effects of C++'s limitations): - - 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. - 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). - 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) - -Finally, you should be **very cautious** when using this feature, as the -decision you make applies to **all** future changes to the mock -class. If an important change is made in the interface you are mocking -(and thus in the mock class), it could break your tests (if you use -`StrictMock`) or let bugs pass through without a warning (if you use -`NiceMock`). Therefore, try to specify the mock's behavior using -explicit `EXPECT_CALL` first, and only turn to `NiceMock` or -`StrictMock` as the last resort. - -## Simplifying the Interface without Breaking Existing Code ## - -Sometimes a method has a long list of arguments that is mostly -uninteresting. For example, - -``` -class LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, - const char* message, size_t message_len) = 0; -}; -``` - -This method's argument list is lengthy and hard to work with (let's -say that the `message` argument is not even 0-terminated). If we mock -it as is, using the mock will be awkward. If, however, we try to -simplify this interface, we'll need to fix all clients depending on -it, which is often infeasible. - -The trick is to re-dispatch the method in the mock class: - -``` -class ScopedMockLog : public LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const tm* tm_time, - const char* message, size_t message_len) { - // We are only interested in the log severity, full file name, and - // log message. - Log(severity, full_filename, std::string(message, message_len)); - } - - // Implements the mock method: - // - // void Log(LogSeverity severity, - // const string& file_path, - // const string& message); - MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, - const string& message)); -}; -``` - -By defining a new mock method with a trimmed argument list, we make -the mock class much more user-friendly. - -## Alternative to Mocking Concrete Classes ## - -Often you may find yourself using classes that don't implement -interfaces. In order to test your code that uses such a class (let's -call it `Concrete`), you may be tempted to make the methods of -`Concrete` virtual and then mock it. - -Try not to do that. - -Making a non-virtual function virtual is a big decision. It creates an -extension point where subclasses can tweak your class' behavior. This -weakens your control on the class because now it's harder to maintain -the class' invariants. You should make a function virtual only when -there is a valid reason for a subclass to override it. - -Mocking concrete classes directly is problematic as it creates a tight -coupling between the class and the tests - any small change in the -class may invalidate your tests and make test maintenance a pain. - -To avoid such problems, many programmers have been practicing "coding -to interfaces": instead of talking to the `Concrete` class, your code -would define an interface and talk to it. Then you implement that -interface as an adaptor on top of `Concrete`. In tests, you can easily -mock that interface to observe how your code is doing. - -This technique incurs some overhead: - - * You pay the cost of virtual function calls (usually not a problem). - * There is more abstraction for the programmers to learn. - -However, it can also bring significant benefits in addition to better -testability: - - * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. - * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. - -Some people worry that if everyone is practicing this technique, they -will end up writing lots of redundant code. This concern is totally -understandable. However, there are two reasons why it may not be the -case: - - * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. - * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. - -You need to weigh the pros and cons carefully for your particular -problem, but I'd like to assure you that the Java community has been -practicing this for a long time and it's a proven effective technique -applicable in a wide variety of situations. :-) - -## Delegating Calls to a Fake ## - -Some times you have a non-trivial fake implementation of an -interface. For example: - -``` -class Foo { - public: - virtual ~Foo() {} - virtual char DoThis(int n) = 0; - virtual void DoThat(const char* s, int* p) = 0; -}; - -class FakeFoo : public Foo { - public: - virtual char DoThis(int n) { - return (n > 0) ? '+' : - (n < 0) ? '-' : '0'; - } - - virtual void DoThat(const char* s, int* p) { - *p = strlen(s); - } -}; -``` - -Now you want to mock this interface such that you can set expectations -on it. However, you also want to use `FakeFoo` for the default -behavior, as duplicating it in the mock object is, well, a lot of -work. - -When you define the mock class using Google Mock, you can have it -delegate its default action to a fake class you already have, using -this pattern: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - // Normal mock method definitions using Google Mock. - MOCK_METHOD1(DoThis, char(int n)); - MOCK_METHOD2(DoThat, void(const char* s, int* p)); - - // Delegates the default actions of the methods to a FakeFoo object. - // This must be called *before* the custom ON_CALL() statements. - void DelegateToFake() { - ON_CALL(*this, DoThis(_)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); - ON_CALL(*this, DoThat(_, _)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); - } - private: - FakeFoo fake_; // Keeps an instance of the fake in the mock. -}; -``` - -With that, you can use `MockFoo` in your tests as usual. Just remember -that if you don't explicitly set an action in an `ON_CALL()` or -`EXPECT_CALL()`, the fake will be called upon to do it: - -``` -using ::testing::_; - -TEST(AbcTest, Xyz) { - MockFoo foo; - foo.DelegateToFake(); // Enables the fake for delegation. - - // Put your ON_CALL(foo, ...)s here, if any. - - // No action specified, meaning to use the default action. - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(foo, DoThat(_, _)); - - int n = 0; - EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. - foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. - EXPECT_EQ(2, n); -} -``` - -**Some tips:** - - * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. - * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. - * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. - * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. - -Regarding the tip on mixing a mock and a fake, here's an example on -why it may be a bad sign: Suppose you have a class `System` for -low-level system operations. In particular, it does file and I/O -operations. And suppose you want to test how your code uses `System` -to do I/O, and you just want the file operations to work normally. If -you mock out the entire `System` class, you'll have to provide a fake -implementation for the file operation part, which suggests that -`System` is taking on too many roles. - -Instead, you can define a `FileOps` interface and an `IOOps` interface -and split `System`'s functionalities into the two. Then you can mock -`IOOps` without mocking `FileOps`. - -## Delegating Calls to a Real Object ## - -When using testing doubles (mocks, fakes, stubs, and etc), sometimes -their behaviors will differ from those of the real objects. This -difference could be either intentional (as in simulating an error such -that you can test the error handling code) or unintentional. If your -mocks have different behaviors than the real objects by mistake, you -could end up with code that passes the tests but fails in production. - -You can use the _delegating-to-real_ technique to ensure that your -mock has the same behavior as the real object while retaining the -ability to validate calls. This technique is very similar to the -delegating-to-fake technique, the difference being that we use a real -object instead of a fake. Here's an example: - -``` -using ::testing::_; -using ::testing::AtLeast; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MockFoo() { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DoThis()) - .WillByDefault(Invoke(&real_, &Foo::DoThis)); - ON_CALL(*this, DoThat(_)) - .WillByDefault(Invoke(&real_, &Foo::DoThat)); - ... - } - MOCK_METHOD0(DoThis, ...); - MOCK_METHOD1(DoThat, ...); - ... - private: - Foo real_; -}; -... - - MockFoo mock; - - EXPECT_CALL(mock, DoThis()) - .Times(3); - EXPECT_CALL(mock, DoThat("Hi")) - .Times(AtLeast(1)); - ... use mock in test ... -``` - -With this, Google Mock will verify that your code made the right calls -(with the right arguments, in the right order, called the right number -of times, etc), and a real object will answer the calls (so the -behavior will be the same as in production). This gives you the best -of both worlds. - -## Delegating Calls to a Parent Class ## - -Ideally, you should code to interfaces, whose methods are all pure -virtual. In reality, sometimes you do need to mock a virtual method -that is not pure (i.e, it already has an implementation). For example: - -``` -class Foo { - public: - virtual ~Foo(); - - virtual void Pure(int n) = 0; - virtual int Concrete(const char* str) { ... } -}; - -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); -}; -``` - -Sometimes you may want to call `Foo::Concrete()` instead of -`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub -action, or perhaps your test doesn't need to mock `Concrete()` at all -(but it would be oh-so painful to have to define a new mock class -whenever you don't need to mock one of its methods). - -The trick is to leave a back door in your mock class for accessing the -real methods in the base class: - -``` -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); - - // Use this to call Concrete() defined in Foo. - int FooConcrete(const char* str) { return Foo::Concrete(str); } -}; -``` - -Now, you can call `Foo::Concrete()` inside an action by: - -``` -using ::testing::_; -using ::testing::Invoke; -... - EXPECT_CALL(foo, Concrete(_)) - .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -or tell the mock object that you don't want to mock `Concrete()`: - -``` -using ::testing::Invoke; -... - ON_CALL(foo, Concrete(_)) - .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do -that, `MockFoo::Concrete()` will be called (and cause an infinite -recursion) since `Foo::Concrete()` is virtual. That's just how C++ -works.) - -# Using Matchers # - -## Matching Argument Values Exactly ## - -You can specify exactly which arguments a mock method is expecting: - -``` -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(5)) - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", bar)); -``` - -## Using Simple Matchers ## - -You can use matchers to match arguments that have a certain property: - -``` -using ::testing::Ge; -using ::testing::NotNull; -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", NotNull())); - // The second argument must not be NULL. -``` - -A frequently used matcher is `_`, which matches anything: - -``` -using ::testing::_; -using ::testing::NotNull; -... - EXPECT_CALL(foo, DoThat(_, NotNull())); -``` - -## Combining Matchers ## - -You can build complex matchers from existing ones using `AllOf()`, -`AnyOf()`, and `Not()`: - -``` -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -... - // The argument must be > 5 and != 10. - EXPECT_CALL(foo, DoThis(AllOf(Gt(5), - Ne(10)))); - - // The first argument must not contain sub-string "blah". - EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), - NULL)); -``` - -## Casting Matchers ## - -Google Mock matchers are statically typed, meaning that the compiler -can catch your mistake if you use a matcher of the wrong type (for -example, if you use `Eq(5)` to match a `string` argument). Good for -you! - -Sometimes, however, you know what you're doing and want the compiler -to give you some slack. One example is that you have a matcher for -`long` and the argument you want to match is `int`. While the two -types aren't exactly the same, there is nothing really wrong with -using a `Matcher` to match an `int` - after all, we can first -convert the `int` argument to a `long` before giving it to the -matcher. - -To support this need, Google Mock gives you the -`SafeMatcherCast(m)` function. It casts a matcher `m` to type -`Matcher`. To ensure safety, Google Mock checks that (let `U` be the -type `m` accepts): - - 1. Type `T` can be implicitly cast to type `U`; - 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and - 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). - -The code won't compile if any of these conditions isn't met. - -Here's one example: - -``` -using ::testing::SafeMatcherCast; - -// A base class and a child class. -class Base { ... }; -class Derived : public Base { ... }; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(DoThis, void(Derived* derived)); -}; -... - - MockFoo foo; - // m is a Matcher we got from somewhere. - EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); -``` - -If you find `SafeMatcherCast(m)` too limiting, you can use a similar -function `MatcherCast(m)`. The difference is that `MatcherCast` works -as long as you can `static_cast` type `T` to type `U`. - -`MatcherCast` essentially lets you bypass C++'s type system -(`static_cast` isn't always safe as it could throw away information, -for example), so be careful not to misuse/abuse it. - -## Selecting Between Overloaded Functions ## - -If you expect an overloaded function to be called, the compiler may -need some help on which overloaded version it is. - -To disambiguate functions overloaded on the const-ness of this object, -use the `Const()` argument wrapper. - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - ... - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -... - - MockFoo foo; - Bar bar1, bar2; - EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). - .WillOnce(ReturnRef(bar1)); - EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). - .WillOnce(ReturnRef(bar2)); -``` - -(`Const()` is defined by Google Mock and returns a `const` reference -to its argument.) - -To disambiguate overloaded functions with the same number of arguments -but different argument types, you may need to specify the exact type -of a matcher, either by wrapping your matcher in `Matcher()`, or -using a matcher whose type is fixed (`TypedEq`, `An()`, -etc): - -``` -using ::testing::An; -using ::testing::Lt; -using ::testing::Matcher; -using ::testing::TypedEq; - -class MockPrinter : public Printer { - public: - MOCK_METHOD1(Print, void(int n)); - MOCK_METHOD1(Print, void(char c)); -}; - -TEST(PrinterTest, Print) { - MockPrinter printer; - - EXPECT_CALL(printer, Print(An())); // void Print(int); - EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); - EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); - - printer.Print(3); - printer.Print(6); - printer.Print('a'); -} -``` - -## Performing Different Actions Based on the Arguments ## - -When a mock method is called, the _last_ matching expectation that's -still active will be selected (think "newer overrides older"). So, you -can make a method do different things depending on its argument values -like this: - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Return; -... - // The default case. - EXPECT_CALL(foo, DoThis(_)) - .WillRepeatedly(Return('b')); - - // The more specific case. - EXPECT_CALL(foo, DoThis(Lt(5))) - .WillRepeatedly(Return('a')); -``` - -Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will -be returned; otherwise `'b'` will be returned. - -## Matching Multiple Arguments as a Whole ## - -Sometimes it's not enough to match the arguments individually. For -example, we may want to say that the first argument must be less than -the second argument. The `With()` clause allows us to match -all arguments of a mock function as a whole. For example, - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Ne; -... - EXPECT_CALL(foo, InRange(Ne(0), _)) - .With(Lt()); -``` - -says that the first argument of `InRange()` must not be 0, and must be -less than the second argument. - -The expression inside `With()` must be a matcher of type -`Matcher >`, where `A1`, ..., `An` are the -types of the function arguments. - -You can also write `AllArgs(m)` instead of `m` inside `.With()`. The -two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable -than `.With(Lt())`. - -You can use `Args(m)` to match the `n` selected arguments -(as a tuple) against `m`. For example, - -``` -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::Lt; -... - EXPECT_CALL(foo, Blah(_, _, _)) - .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); -``` - -says that `Blah()` will be called with arguments `x`, `y`, and `z` where -`x < y < z`. - -As a convenience and example, Google Mock provides some matchers for -2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_6_CheatSheet.md) for -the complete list. - -Note that if you want to pass the arguments to a predicate of your own -(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be -written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` -selected arguments as _one_ single tuple to the predicate. - -## Using Matchers as Predicates ## - -Have you noticed that a matcher is just a fancy predicate that also -knows how to describe itself? Many existing algorithms take predicates -as arguments (e.g. those defined in STL's `` header), and -it would be a shame if Google Mock matchers are not allowed to -participate. - -Luckily, you can use a matcher where a unary predicate functor is -expected by wrapping it inside the `Matches()` function. For example, - -``` -#include -#include - -std::vector v; -... -// How many elements in v are >= 10? -const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); -``` - -Since you can build complex matchers from simpler ones easily using -Google Mock, this gives you a way to conveniently construct composite -predicates (doing the same using STL's `` header is just -painful). For example, here's a predicate that's satisfied by any -number that is >= 0, <= 100, and != 50: - -``` -Matches(AllOf(Ge(0), Le(100), Ne(50))) -``` - -## Using Matchers in Google Test Assertions ## - -Since matchers are basically predicates that also know how to describe -themselves, there is a way to take advantage of them in -[Google Test](http://code.google.com/p/googletest/) assertions. It's -called `ASSERT_THAT` and `EXPECT_THAT`: - -``` - ASSERT_THAT(value, matcher); // Asserts that value matches matcher. - EXPECT_THAT(value, matcher); // The non-fatal version. -``` - -For example, in a Google Test test you can write: - -``` -#include "gmock/gmock.h" - -using ::testing::AllOf; -using ::testing::Ge; -using ::testing::Le; -using ::testing::MatchesRegex; -using ::testing::StartsWith; -... - - EXPECT_THAT(Foo(), StartsWith("Hello")); - EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); - ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); -``` - -which (as you can probably guess) executes `Foo()`, `Bar()`, and -`Baz()`, and verifies that: - - * `Foo()` returns a string that starts with `"Hello"`. - * `Bar()` returns a string that matches regular expression `"Line \\d+"`. - * `Baz()` returns a number in the range [5, 10]. - -The nice thing about these macros is that _they read like -English_. They generate informative messages too. For example, if the -first `EXPECT_THAT()` above fails, the message will be something like: - -``` -Value of: Foo() - Actual: "Hi, world!" -Expected: starts with "Hello" -``` - -**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the -[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds -`assertThat()` to JUnit. - -## Using Predicates as Matchers ## - -Google Mock provides a built-in set of matchers. In case you find them -lacking, you can use an arbitray unary predicate function or functor -as a matcher - as long as the predicate accepts a value of the type -you want. You do this by wrapping the predicate inside the `Truly()` -function, for example: - -``` -using ::testing::Truly; - -int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } -... - - // Bar() must be called with an even number. - EXPECT_CALL(foo, Bar(Truly(IsEven))); -``` - -Note that the predicate function / functor doesn't have to return -`bool`. It works as long as the return value can be used as the -condition in statement `if (condition) ...`. - -## Matching Arguments that Are Not Copyable ## - -When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves -away a copy of `bar`. When `Foo()` is called later, Google Mock -compares the argument to `Foo()` with the saved copy of `bar`. This -way, you don't need to worry about `bar` being modified or destroyed -after the `EXPECT_CALL()` is executed. The same is true when you use -matchers like `Eq(bar)`, `Le(bar)`, and so on. - -But what if `bar` cannot be copied (i.e. has no copy constructor)? You -could define your own matcher function and use it with `Truly()`, as -the previous couple of recipes have shown. Or, you may be able to get -away from it if you can guarantee that `bar` won't be changed after -the `EXPECT_CALL()` is executed. Just tell Google Mock that it should -save a reference to `bar`, instead of a copy of it. Here's how: - -``` -using ::testing::Eq; -using ::testing::ByRef; -using ::testing::Lt; -... - // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); - - // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); -``` - -Remember: if you do this, don't change `bar` after the -`EXPECT_CALL()`, or the result is undefined. - -## Validating a Member of an Object ## - -Often a mock function takes a reference to object as an argument. When -matching the argument, you may not want to compare the entire object -against a fixed object, as that may be over-specification. Instead, -you may need to validate a certain member variable or the result of a -certain getter method of the object. You can do this with `Field()` -and `Property()`. More specifically, - -``` -Field(&Foo::bar, m) -``` - -is a matcher that matches a `Foo` object whose `bar` member variable -satisfies matcher `m`. - -``` -Property(&Foo::baz, m) -``` - -is a matcher that matches a `Foo` object whose `baz()` method returns -a value that satisfies matcher `m`. - -For example: - -> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | -|:-----------------------------|:-----------------------------------| -> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | - -Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no -argument and be declared as `const`. - -BTW, `Field()` and `Property()` can also match plain pointers to -objects. For instance, - -``` -Field(&Foo::number, Ge(3)) -``` - -matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, -the match will always fail regardless of the inner matcher. - -What if you want to validate more than one members at the same time? -Remember that there is `AllOf()`. - -## Validating the Value Pointed to by a Pointer Argument ## - -C++ functions often take pointers as arguments. You can use matchers -like `NULL`, `NotNull()`, and other comparison matchers to match a -pointer, but what if you want to make sure the value _pointed to_ by -the pointer, instead of the pointer itself, has a certain property? -Well, you can use the `Pointee(m)` matcher. - -`Pointee(m)` matches a pointer iff `m` matches the value the pointer -points to. For example: - -``` -using ::testing::Ge; -using ::testing::Pointee; -... - EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); -``` - -expects `foo.Bar()` to be called with a pointer that points to a value -greater than or equal to 3. - -One nice thing about `Pointee()` is that it treats a `NULL` pointer as -a match failure, so you can write `Pointee(m)` instead of - -``` - AllOf(NotNull(), Pointee(m)) -``` - -without worrying that a `NULL` pointer will crash your test. - -Also, did we tell you that `Pointee()` works with both raw pointers -**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and -etc)? - -What if you have a pointer to pointer? You guessed it - you can use -nested `Pointee()` to probe deeper inside the value. For example, -`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer -that points to a number less than 3 (what a mouthful...). - -## Testing a Certain Property of an Object ## - -Sometimes you want to specify that an object argument has a certain -property, but there is no existing matcher that does this. If you want -good error messages, you should define a matcher. If you want to do it -quick and dirty, you could get away with writing an ordinary function. - -Let's say you have a mock function that takes an object of type `Foo`, -which has an `int bar()` method and an `int baz()` method, and you -want to constrain that the argument's `bar()` value plus its `baz()` -value is a given number. Here's how you can define a matcher to do it: - -``` -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class BarPlusBazEqMatcher : public MatcherInterface { - public: - explicit BarPlusBazEqMatcher(int expected_sum) - : expected_sum_(expected_sum) {} - - virtual bool MatchAndExplain(const Foo& foo, - MatchResultListener* listener) const { - return (foo.bar() + foo.baz()) == expected_sum_; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "bar() + baz() equals " << expected_sum_; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "bar() + baz() does not equal " << expected_sum_; - } - private: - const int expected_sum_; -}; - -inline Matcher BarPlusBazEq(int expected_sum) { - return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); -} - -... - - EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; -``` - -## Matching Containers ## - -Sometimes an STL container (e.g. list, vector, map, ...) is passed to -a mock function and you may want to validate it. Since most STL -containers support the `==` operator, you can write -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. - -Sometimes, though, you may want to be more flexible (for example, the -first element must be an exact match, but the second element can be -any positive number, and so on). Also, containers used in tests often -have a small number of elements, and having to define the expected -container out-of-line is a bit of a hassle. - -You can use the `ElementsAre()` matcher in such cases: - -``` -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::Gt; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); -``` - -The above matcher says that the container must have 4 elements, which -must be 1, greater than 0, anything, and 5 respectively. - -`ElementsAre()` is overloaded to take 0 to 10 arguments. If more are -needed, you can place them in a C-style array and use -`ElementsAreArray()` instead: - -``` -using ::testing::ElementsAreArray; -... - - // ElementsAreArray accepts an array of element values. - const int expected_vector1[] = { 1, 5, 2, 4, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); - - // Or, an array of element matchers. - Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); -``` - -In case the array needs to be dynamically created (and therefore the -array size cannot be inferred by the compiler), you can give -`ElementsAreArray()` an additional argument to specify the array size: - -``` -using ::testing::ElementsAreArray; -... - int* const expected_vector3 = new int[count]; - ... fill expected_vector3 with values ... - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); -``` - -**Tips:** - - * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. - * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. - * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. - * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). - -## Sharing Matchers ## - -Under the hood, a Google Mock matcher object consists of a pointer to -a ref-counted implementation object. Copying matchers is allowed and -very efficient, as only the pointer is copied. When the last matcher -that references the implementation object dies, the implementation -object will be deleted. - -Therefore, if you have some complex matcher that you want to use again -and again, there is no need to build it everytime. Just assign it to a -matcher variable and use that variable repeatedly! For example, - -``` - Matcher in_range = AllOf(Gt(5), Le(10)); - ... use in_range as a matcher in multiple EXPECT_CALLs ... -``` - -# Setting Expectations # - -## Ignoring Uninteresting Calls ## - -If you are not interested in how a mock method is called, just don't -say anything about it. In this case, if the method is ever called, -Google Mock will perform its default action to allow the test program -to continue. If you are not happy with the default action taken by -Google Mock, you can override it using `DefaultValue::Set()` -(described later in this document) or `ON_CALL()`. - -Please note that once you expressed interest in a particular mock -method (via `EXPECT_CALL()`), all invocations to it must match some -expectation. If this function is called but the arguments don't match -any `EXPECT_CALL()` statement, it will be an error. - -## Disallowing Unexpected Calls ## - -If a mock method shouldn't be called at all, explicitly say so: - -``` -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -If some calls to the method are allowed, but the rest are not, just -list all the expected calls: - -``` -using ::testing::AnyNumber; -using ::testing::Gt; -... - EXPECT_CALL(foo, Bar(5)); - EXPECT_CALL(foo, Bar(Gt(10))) - .Times(AnyNumber()); -``` - -A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` -statements will be an error. - -## Expecting Ordered Calls ## - -Although an `EXPECT_CALL()` statement defined earlier takes precedence -when Google Mock tries to match a function call with an expectation, -by default calls don't have to happen in the order `EXPECT_CALL()` -statements are written. For example, if the arguments match the -matchers in the third `EXPECT_CALL()`, but not those in the first two, -then the third expectation will be used. - -If you would rather have all calls occur in the order of the -expectations, put the `EXPECT_CALL()` statements in a block where you -define a variable of type `InSequence`: - -``` - using ::testing::_; - using ::testing::InSequence; - - { - InSequence s; - - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(bar, DoThat(_)) - .Times(2); - EXPECT_CALL(foo, DoThis(6)); - } -``` - -In this example, we expect a call to `foo.DoThis(5)`, followed by two -calls to `bar.DoThat()` where the argument can be anything, which are -in turn followed by a call to `foo.DoThis(6)`. If a call occurred -out-of-order, Google Mock will report an error. - -## Expecting Partially Ordered Calls ## - -Sometimes requiring everything to occur in a predetermined order can -lead to brittle tests. For example, we may care about `A` occurring -before both `B` and `C`, but aren't interested in the relative order -of `B` and `C`. In this case, the test should reflect our real intent, -instead of being overly constraining. - -Google Mock allows you to impose an arbitrary DAG (directed acyclic -graph) on the calls. One way to express the DAG is to use the -[After](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. - -Another way is via the `InSequence()` clause (not the same as the -`InSequence` class), which we borrowed from jMock 2. It's less -flexible than `After()`, but more convenient when you have long chains -of sequential calls, as it doesn't require you to come up with -different names for the expectations in the chains. Here's how it -works: - -If we view `EXPECT_CALL()` statements as nodes in a graph, and add an -edge from node A to node B wherever A must occur before B, we can get -a DAG. We use the term "sequence" to mean a directed path in this -DAG. Now, if we decompose the DAG into sequences, we just need to know -which sequences each `EXPECT_CALL()` belongs to in order to be able to -reconstruct the orginal DAG. - -So, to specify the partial order on the expectations we need to do two -things: first to define some `Sequence` objects, and then for each -`EXPECT_CALL()` say which `Sequence` objects it is part -of. Expectations in the same sequence must occur in the order they are -written. For example, - -``` - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(foo, A()) - .InSequence(s1, s2); - EXPECT_CALL(bar, B()) - .InSequence(s1); - EXPECT_CALL(bar, C()) - .InSequence(s2); - EXPECT_CALL(foo, D()) - .InSequence(s2); -``` - -specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> -C -> D`): - -``` - +---> B - | - A ---| - | - +---> C ---> D -``` - -This means that A must occur before B and C, and C must occur before -D. There's no restriction about the order other than these. - -## Controlling When an Expectation Retires ## - -When a mock method is called, Google Mock only consider expectations -that are still active. An expectation is active when created, and -becomes inactive (aka _retires_) when a call that has to occur later -has occurred. For example, in - -``` - using ::testing::_; - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 - .Times(AnyNumber()) - .InSequence(s1, s2); - EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 - .InSequence(s1); - EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 - .InSequence(s2); -``` - -as soon as either #2 or #3 is matched, #1 will retire. If a warning -`"File too large."` is logged after this, it will be an error. - -Note that an expectation doesn't retire automatically when it's -saturated. For example, - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 -``` - -says that there will be exactly one warning with the message `"File -too large."`. If the second warning contains this message too, #2 will -match again and result in an upper-bound-violated error. - -If this is not what you want, you can ask an expectation to retire as -soon as it becomes saturated: - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 - .RetiresOnSaturation(); -``` - -Here #2 can be used only once, so if you have two warnings with the -message `"File too large."`, the first will match #2 and the second -will match #1 - there will be no error. - -# Using Actions # - -## Returning References from Mock Methods ## - -If a mock function's return type is a reference, you need to use -`ReturnRef()` instead of `Return()` to return a result: - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetBar, Bar&()); -}; -... - - MockFoo foo; - Bar bar; - EXPECT_CALL(foo, GetBar()) - .WillOnce(ReturnRef(bar)); -``` - -## Returning Live Values from Mock Methods ## - -The `Return(x)` action saves a copy of `x` when the action is -_created_, and always returns the same value whenever it's -executed. Sometimes you may want to instead return the _live_ value of -`x` (i.e. its value at the time when the action is _executed_.). - -If the mock function's return type is a reference, you can do it using -`ReturnRef(x)`, as shown in the previous recipe ("Returning References -from Mock Methods"). However, Google Mock doesn't let you use -`ReturnRef()` in a mock function whose return type is not a reference, -as doing that usually indicates a user error. So, what shall you do? - -You may be tempted to try `ByRef()`: - -``` -using testing::ByRef; -using testing::Return; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetValue, int()); -}; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(Return(ByRef(x))); - x = 42; - EXPECT_EQ(42, foo.GetValue()); -``` - -Unfortunately, it doesn't work here. The above code will fail with error: - -``` -Value of: foo.GetValue() - Actual: 0 -Expected: 42 -``` - -The reason is that `Return(value)` converts `value` to the actual -return type of the mock function at the time when the action is -_created_, not when it is _executed_. (This behavior was chosen for -the action to be safe when `value` is a proxy object that references -some temporary objects.) As a result, `ByRef(x)` is converted to an -`int` value (instead of a `const int&`) when the expectation is set, -and `Return(ByRef(x))` will always return 0. - -`ReturnPointee(pointer)` was provided to solve this problem -specifically. It returns the value pointed to by `pointer` at the time -the action is _executed_: - -``` -using testing::ReturnPointee; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(ReturnPointee(&x)); // Note the & here. - x = 42; - EXPECT_EQ(42, foo.GetValue()); // This will succeed now. -``` - -## Combining Actions ## - -Want to do more than one thing when a function is called? That's -fine. `DoAll()` allow you to do sequence of actions every time. Only -the return value of the last action in the sequence will be used. - -``` -using ::testing::DoAll; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Bar, bool(int n)); -}; -... - - EXPECT_CALL(foo, Bar(_)) - .WillOnce(DoAll(action_1, - action_2, - ... - action_n)); -``` - -## Mocking Side Effects ## - -Sometimes a method exhibits its effect not via returning a value but -via side effects. For example, it may change some global state or -modify an output argument. To mock side effects, in general you can -define your own action by implementing `::testing::ActionInterface`. - -If all you need to do is to change an output argument, the built-in -`SetArgPointee()` action is convenient: - -``` -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - MOCK_METHOD2(Mutate, void(bool mutate, int* value)); - ... -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, Mutate(true, _)) - .WillOnce(SetArgPointee<1>(5)); -``` - -In this example, when `mutator.Mutate()` is called, we will assign 5 -to the `int` variable pointed to by argument #1 -(0-based). - -`SetArgPointee()` conveniently makes an internal copy of the -value you pass to it, removing the need to keep the value in scope and -alive. The implication however is that the value must have a copy -constructor and assignment operator. - -If the mock method also needs to return a value as well, you can chain -`SetArgPointee()` with `Return()` using `DoAll()`: - -``` -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - ... - MOCK_METHOD1(MutateInt, bool(int* value)); -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, MutateInt(_)) - .WillOnce(DoAll(SetArgPointee<0>(5), - Return(true))); -``` - -If the output argument is an array, use the -`SetArrayArgument(first, last)` action instead. It copies the -elements in source range `[first, last)` to the array pointed to by -the `N`-th (0-based) argument: - -``` -using ::testing::NotNull; -using ::testing::SetArrayArgument; - -class MockArrayMutator : public ArrayMutator { - public: - MOCK_METHOD2(Mutate, void(int* values, int num_values)); - ... -}; -... - - MockArrayMutator mutator; - int values[5] = { 1, 2, 3, 4, 5 }; - EXPECT_CALL(mutator, Mutate(NotNull(), 5)) - .WillOnce(SetArrayArgument<0>(values, values + 5)); -``` - -This also works when the argument is an output iterator: - -``` -using ::testing::_; -using ::testing::SeArrayArgument; - -class MockRolodex : public Rolodex { - public: - MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); - ... -}; -... - - MockRolodex rolodex; - vector names; - names.push_back("George"); - names.push_back("John"); - names.push_back("Thomas"); - EXPECT_CALL(rolodex, GetNames(_)) - .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); -``` - -## Changing a Mock Object's Behavior Based on the State ## - -If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: - -``` -using ::testing::InSequence; -using ::testing::Return; - -... - { - InSequence seq; - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(my_mock, Flush()); - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(false)); - } - my_mock.FlushIfDirty(); -``` - -This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. - -If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: - -``` -using ::testing::_; -using ::testing::SaveArg; -using ::testing::Return; - -ACTION_P(ReturnPointee, p) { return *p; } -... - int previous_value = 0; - EXPECT_CALL(my_mock, GetPrevValue()) - .WillRepeatedly(ReturnPointee(&previous_value)); - EXPECT_CALL(my_mock, UpdateValue(_)) - .WillRepeatedly(SaveArg<0>(&previous_value)); - my_mock.DoSomethingToUpdateValue(); -``` - -Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. - -## Setting the Default Value for a Return Type ## - -If a mock method's return type is a built-in C++ type or pointer, by -default it will return 0 when invoked. You only need to specify an -action if this default value doesn't work for you. - -Sometimes, you may want to change this default value, or you may want -to specify a default value for types Google Mock doesn't know -about. You can do this using the `::testing::DefaultValue` class -template: - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD0(CalculateBar, Bar()); -}; -... - - Bar default_bar; - // Sets the default return value for type Bar. - DefaultValue::Set(default_bar); - - MockFoo foo; - - // We don't need to specify an action here, as the default - // return value works for us. - EXPECT_CALL(foo, CalculateBar()); - - foo.CalculateBar(); // This should return default_bar. - - // Unsets the default return value. - DefaultValue::Clear(); -``` - -Please note that changing the default value for a type can make you -tests hard to understand. We recommend you to use this feature -judiciously. For example, you may want to make sure the `Set()` and -`Clear()` calls are right next to the code that uses your mock. - -## Setting the Default Actions for a Mock Method ## - -You've learned how to change the default value of a given -type. However, this may be too coarse for your purpose: perhaps you -have two mock methods with the same return type and you want them to -have different behaviors. The `ON_CALL()` macro allows you to -customize your mock's behavior at the method level: - -``` -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Gt; -using ::testing::Return; -... - ON_CALL(foo, Sign(_)) - .WillByDefault(Return(-1)); - ON_CALL(foo, Sign(0)) - .WillByDefault(Return(0)); - ON_CALL(foo, Sign(Gt(0))) - .WillByDefault(Return(1)); - - EXPECT_CALL(foo, Sign(_)) - .Times(AnyNumber()); - - foo.Sign(5); // This should return 1. - foo.Sign(-9); // This should return -1. - foo.Sign(0); // This should return 0. -``` - -As you may have guessed, when there are more than one `ON_CALL()` -statements, the news order take precedence over the older ones. In -other words, the **last** one that matches the function arguments will -be used. This matching order allows you to set up the common behavior -in a mock object's constructor or the test fixture's set-up phase and -specialize the mock's behavior later. - -## Using Functions/Methods/Functors as Actions ## - -If the built-in actions don't suit you, you can easily use an existing -function, method, or functor as an action: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(Sum, int(int x, int y)); - MOCK_METHOD1(ComplexJob, bool(int x)); -}; - -int CalculateSum(int x, int y) { return x + y; } - -class Helper { - public: - bool ComplexJob(int x); -}; -... - - MockFoo foo; - Helper helper; - EXPECT_CALL(foo, Sum(_, _)) - .WillOnce(Invoke(CalculateSum)); - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(Invoke(&helper, &Helper::ComplexJob)); - - foo.Sum(5, 6); // Invokes CalculateSum(5, 6). - foo.ComplexJob(10); // Invokes helper.ComplexJob(10); -``` - -The only requirement is that the type of the function, etc must be -_compatible_ with the signature of the mock function, meaning that the -latter's arguments can be implicitly converted to the corresponding -arguments of the former, and the former's return type can be -implicitly converted to that of the latter. So, you can invoke -something whose type is _not_ exactly the same as the mock function, -as long as it's safe to do so - nice, huh? - -## Invoking a Function/Method/Functor Without Arguments ## - -`Invoke()` is very useful for doing actions that are more complex. It -passes the mock function's arguments to the function or functor being -invoked such that the callee has the full context of the call to work -with. If the invoked function is not interested in some or all of the -arguments, it can simply ignore them. - -Yet, a common pattern is that a test author wants to invoke a function -without the arguments of the mock function. `Invoke()` allows her to -do that using a wrapper function that throws away the arguments before -invoking an underlining nullary function. Needless to say, this can be -tedious and obscures the intent of the test. - -`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except -that it doesn't pass the mock function's arguments to the -callee. Here's an example: - -``` -using ::testing::_; -using ::testing::InvokeWithoutArgs; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(ComplexJob, bool(int n)); -}; - -bool Job1() { ... } -... - - MockFoo foo; - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(InvokeWithoutArgs(Job1)); - - foo.ComplexJob(10); // Invokes Job1(). -``` - -## Invoking an Argument of the Mock Function ## - -Sometimes a mock function will receive a function pointer or a functor -(in other words, a "callable") as an argument, e.g. - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); -}; -``` - -and you may want to invoke this callable argument: - -``` -using ::testing::_; -... - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(...); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -Arghh, you need to refer to a mock function argument but C++ has no -lambda (yet), so you have to define your own action. :-( Or do you -really? - -Well, Google Mock has an action to solve _exactly_ this problem: - -``` - InvokeArgument(arg_1, arg_2, ..., arg_m) -``` - -will invoke the `N`-th (0-based) argument the mock function receives, -with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is -a function pointer or a functor, Google Mock handles them both. - -With that, you could write: - -``` -using ::testing::_; -using ::testing::InvokeArgument; -... - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(InvokeArgument<1>(5)); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -What if the callable takes an argument by reference? No problem - just -wrap it inside `ByRef()`: - -``` -... - MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); -... -using ::testing::_; -using ::testing::ByRef; -using ::testing::InvokeArgument; -... - - MockFoo foo; - Helper helper; - ... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, ByRef(helper))); - // ByRef(helper) guarantees that a reference to helper, not a copy of it, - // will be passed to the callable. -``` - -What if the callable takes an argument by reference and we do **not** -wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a -copy_ of the argument, and pass a _reference to the copy_, instead of -a reference to the original value, to the callable. This is especially -handy when the argument is a temporary value: - -``` -... - MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); -... -using ::testing::_; -using ::testing::InvokeArgument; -... - - MockFoo foo; - ... - EXPECT_CALL(foo, DoThat(_)) - .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); - // Will execute (*f)(5.0, string("Hi")), where f is the function pointer - // DoThat() receives. Note that the values 5.0 and string("Hi") are - // temporary and dead once the EXPECT_CALL() statement finishes. Yet - // it's fine to perform this action later, since a copy of the values - // are kept inside the InvokeArgument action. -``` - -## Ignoring an Action's Result ## - -Sometimes you have an action that returns _something_, but you need an -action that returns `void` (perhaps you want to use it in a mock -function that returns `void`, or perhaps it needs to be used in -`DoAll()` and it's not the last in the list). `IgnoreResult()` lets -you do that. For example: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; - -int Process(const MyData& data); -string DoSomething(); - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Abc, void(const MyData& data)); - MOCK_METHOD0(Xyz, bool()); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, Abc(_)) - // .WillOnce(Invoke(Process)); - // The above line won't compile as Process() returns int but Abc() needs - // to return void. - .WillOnce(IgnoreResult(Invoke(Process))); - - EXPECT_CALL(foo, Xyz()) - .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), - // Ignores the string DoSomething() returns. - Return(true))); -``` - -Note that you **cannot** use `IgnoreResult()` on an action that already -returns `void`. Doing so will lead to ugly compiler errors. - -## Selecting an Action's Arguments ## - -Say you have a mock function `Foo()` that takes seven arguments, and -you have a custom action that you want to invoke when `Foo()` is -called. Trouble is, the custom action only wants three arguments: - -``` -using ::testing::_; -using ::testing::Invoke; -... - MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight)); -... - -bool IsVisibleInQuadrant1(bool visible, int x, int y) { - return visible && x >= 0 && y >= 0; -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( -``` - -To please the compiler God, you can to define an "adaptor" that has -the same signature as `Foo()` and calls the custom action with the -right arguments: - -``` -using ::testing::_; -using ::testing::Invoke; - -bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight) { - return IsVisibleInQuadrant1(visible, x, y); -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. -``` - -But isn't this awkward? - -Google Mock provides a generic _action adaptor_, so you can spend your -time minding more important business than writing your own -adaptors. Here's the syntax: - -``` - WithArgs(action) -``` - -creates an action that passes the arguments of the mock function at -the given indices (0-based) to the inner `action` and performs -it. Using `WithArgs`, our original example can be written as: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::WithArgs; -... - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); - // No need to define your own adaptor. -``` - -For better readability, Google Mock also gives you: - - * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and - * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. - -As you may have realized, `InvokeWithoutArgs(...)` is just syntactic -sugar for `WithoutArgs(Inovke(...))`. - -Here are more tips: - - * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. - * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. - * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. - * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. - -## Ignoring Arguments in Action Functions ## - -The selecting-an-action's-arguments recipe showed us one way to make a -mock function and an action with incompatible argument lists fit -together. The downside is that wrapping the action in -`WithArgs<...>()` can get tedious for people writing the tests. - -If you are defining a function, method, or functor to be used with -`Invoke*()`, and you are not interested in some of its arguments, an -alternative to `WithArgs` is to declare the uninteresting arguments as -`Unused`. This makes the definition less cluttered and less fragile in -case the types of the uninteresting arguments change. It could also -increase the chance the action function can be reused. For example, -given - -``` - MOCK_METHOD3(Foo, double(const string& label, double x, double y)); - MOCK_METHOD3(Bar, double(int index, double x, double y)); -``` - -instead of - -``` -using ::testing::_; -using ::testing::Invoke; - -double DistanceToOriginWithLabel(const string& label, double x, double y) { - return sqrt(x*x + y*y); -} - -double DistanceToOriginWithIndex(int index, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOriginWithLabel)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOriginWithIndex)); -``` - -you could write - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Unused; - -double DistanceToOrigin(Unused, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOrigin)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOrigin)); -``` - -## Sharing Actions ## - -Just like matchers, a Google Mock action object consists of a pointer -to a ref-counted implementation object. Therefore copying actions is -also allowed and very efficient. When the last action that references -the implementation object dies, the implementation object will be -deleted. - -If you have some complex action that you want to use again and again, -you may not have to build it from scratch everytime. If the action -doesn't have an internal state (i.e. if it always does the same thing -no matter how many times it has been called), you can assign it to an -action variable and use that variable repeatedly. For example: - -``` - Action set_flag = DoAll(SetArgPointee<0>(5), - Return(true)); - ... use set_flag in .WillOnce() and .WillRepeatedly() ... -``` - -However, if the action has its own state, you may be surprised if you -share the action object. Suppose you have an action factory -`IncrementCounter(init)` which creates an action that increments and -returns a counter whose initial value is `init`, using two actions -created from the same expression and using a shared action will -exihibit different behaviors. Example: - -``` - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(IncrementCounter(0)); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(IncrementCounter(0)); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 1 - Blah() uses a different - // counter than Bar()'s. -``` - -versus - -``` - Action increment = IncrementCounter(0); - - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(increment); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(increment); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 3 - the counter is shared. -``` - -# Misc Recipes on Using Google Mock # - -## Making the Compilation Faster ## - -Believe it or not, the _vast majority_ of the time spent on compiling -a mock class is in generating its constructor and destructor, as they -perform non-trivial tasks (e.g. verification of the -expectations). What's more, mock methods with different signatures -have different types and thus their constructors/destructors need to -be generated by the compiler separately. As a result, if you mock many -different types of methods, compiling your mock class can get really -slow. - -If you are experiencing slow compilation, you can move the definition -of your mock class' constructor and destructor out of the class body -and into a `.cpp` file. This way, even if you `#include` your mock -class in N files, the compiler only needs to generate its constructor -and destructor once, resulting in a much faster compilation. - -Let's illustrate the idea using an example. Here's the definition of a -mock class before applying this recipe: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // Since we don't declare the constructor or the destructor, - // the compiler will generate them in every translation unit - // where this mock class is used. - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` - -After the change, it would look like: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // The constructor and destructor are declared, but not defined, here. - MockFoo(); - virtual ~MockFoo(); - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` -and -``` -// File mock_foo.cpp. -#include "path/to/mock_foo.h" - -// The definitions may appear trivial, but the functions actually do a -// lot of things through the constructors/destructors of the member -// variables used to implement the mock methods. -MockFoo::MockFoo() {} -MockFoo::~MockFoo() {} -``` - -## Forcing a Verification ## - -When it's being destoyed, your friendly mock object will automatically -verify that all expectations on it have been satisfied, and will -generate [Google Test](http://code.google.com/p/googletest/) failures -if not. This is convenient as it leaves you with one less thing to -worry about. That is, unless you are not sure if your mock object will -be destoyed. - -How could it be that your mock object won't eventually be destroyed? -Well, it might be created on the heap and owned by the code you are -testing. Suppose there's a bug in that code and it doesn't delete the -mock object properly - you could end up with a passing test when -there's actually a bug. - -Using a heap checker is a good idea and can alleviate the concern, but -its implementation may not be 100% reliable. So, sometimes you do want -to _force_ Google Mock to verify a mock object before it is -(hopefully) destructed. You can do this with -`Mock::VerifyAndClearExpectations(&mock_object)`: - -``` -TEST(MyServerTest, ProcessesRequest) { - using ::testing::Mock; - - MockFoo* const foo = new MockFoo; - EXPECT_CALL(*foo, ...)...; - // ... other expectations ... - - // server now owns foo. - MyServer server(foo); - server.ProcessRequest(...); - - // In case that server's destructor will forget to delete foo, - // this will verify the expectations anyway. - Mock::VerifyAndClearExpectations(foo); -} // server is destroyed when it goes out of scope here. -``` - -**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a -`bool` to indicate whether the verification was successful (`true` for -yes), so you can wrap that function call inside a `ASSERT_TRUE()` if -there is no point going further when the verification has failed. - -## Using Check Points ## - -Sometimes you may want to "reset" a mock object at various check -points in your test: at each check point, you verify that all existing -expectations on the mock object have been satisfied, and then you set -some new expectations on it as if it's newly created. This allows you -to work with a mock object in "phases" whose sizes are each -manageable. - -One such scenario is that in your test's `SetUp()` function, you may -want to put the object you are testing into a certain state, with the -help from a mock object. Once in the desired state, you want to clear -all expectations on the mock, such that in the `TEST_F` body you can -set fresh expectations on it. - -As you may have figured out, the `Mock::VerifyAndClearExpectations()` -function we saw in the previous recipe can help you here. Or, if you -are using `ON_CALL()` to set default actions on the mock object and -want to clear the default actions as well, use -`Mock::VerifyAndClear(&mock_object)` instead. This function does what -`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the -same `bool`, **plus** it clears the `ON_CALL()` statements on -`mock_object` too. - -Another trick you can use to achieve the same effect is to put the -expectations in sequences and insert calls to a dummy "check-point" -function at specific places. Then you can verify that the mock -function calls do happen at the right time. For example, if you are -exercising code: - -``` -Foo(1); -Foo(2); -Foo(3); -``` - -and want to verify that `Foo(1)` and `Foo(3)` both invoke -`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: - -``` -using ::testing::MockFunction; - -TEST(FooTest, InvokesBarCorrectly) { - MyMock mock; - // Class MockFunction has exactly one mock method. It is named - // Call() and has type F. - MockFunction check; - { - InSequence s; - - EXPECT_CALL(mock, Bar("a")); - EXPECT_CALL(check, Call("1")); - EXPECT_CALL(check, Call("2")); - EXPECT_CALL(mock, Bar("a")); - } - Foo(1); - check.Call("1"); - Foo(2); - check.Call("2"); - Foo(3); -} -``` - -The expectation spec says that the first `Bar("a")` must happen before -check point "1", the second `Bar("a")` must happen after check point "2", -and nothing should happen between the two check points. The explicit -check points make it easy to tell which `Bar("a")` is called by which -call to `Foo()`. - -## Mocking Destructors ## - -Sometimes you want to make sure a mock object is destructed at the -right time, e.g. after `bar->A()` is called but before `bar->B()` is -called. We already know that you can specify constraints on the order -of mock function calls, so all we need to do is to mock the destructor -of the mock function. - -This sounds simple, except for one problem: a destructor is a special -function with special syntax and special semantics, and the -`MOCK_METHOD0` macro doesn't work for it: - -``` - MOCK_METHOD0(~MockFoo, void()); // Won't compile! -``` - -The good news is that you can use a simple pattern to achieve the same -effect. First, add a mock function `Die()` to your mock class and call -it in the destructor, like this: - -``` -class MockFoo : public Foo { - ... - // Add the following two lines to the mock class. - MOCK_METHOD0(Die, void()); - virtual ~MockFoo() { Die(); } -}; -``` - -(If the name `Die()` clashes with an existing symbol, choose another -name.) Now, we have translated the problem of testing when a `MockFoo` -object dies to testing when its `Die()` method is called: - -``` - MockFoo* foo = new MockFoo; - MockBar* bar = new MockBar; - ... - { - InSequence s; - - // Expects *foo to die after bar->A() and before bar->B(). - EXPECT_CALL(*bar, A()); - EXPECT_CALL(*foo, Die()); - EXPECT_CALL(*bar, B()); - } -``` - -And that's that. - -## Using Google Mock and Threads ## - -**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on -platforms where Google Mock is thread-safe. Currently these are only -platforms that support the pthreads library (this includes Linux and Mac). -To make it thread-safe on other platforms we only need to implement -some synchronization operations in `"gtest/internal/gtest-port.h"`. - -In a **unit** test, it's best if you could isolate and test a piece of -code in a single-threaded context. That avoids race conditions and -dead locks, and makes debugging your test much easier. - -Yet many programs are multi-threaded, and sometimes to test something -we need to pound on it from more than one thread. Google Mock works -for this purpose too. - -Remember the steps for using a mock: - - 1. Create a mock object `foo`. - 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. - 1. The code under test calls methods of `foo`. - 1. Optionally, verify and reset the mock. - 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. - -If you follow the following simple rules, your mocks and threads can -live happily togeter: - - * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. - * Obviously, you can do step #1 without locking. - * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? - * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. - -If you violate the rules (for example, if you set expectations on a -mock while another thread is calling its methods), you get undefined -behavior. That's not fun, so don't do it. - -Google Mock guarantees that the action for a mock function is done in -the same thread that called the mock function. For example, in - -``` - EXPECT_CALL(mock, Foo(1)) - .WillOnce(action1); - EXPECT_CALL(mock, Foo(2)) - .WillOnce(action2); -``` - -if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, -Google Mock will execute `action1` in thread 1 and `action2` in thread -2. - -Google Mock does _not_ impose a sequence on actions performed in -different threads (doing so may create deadlocks as the actions may -need to cooperate). This means that the execution of `action1` and -`action2` in the above example _may_ interleave. If this is a problem, -you should add proper synchronization logic to `action1` and `action2` -to make the test thread-safe. - - -Also, remember that `DefaultValue` is a global resource that -potentially affects _all_ living mock objects in your -program. Naturally, you won't want to mess with it from multiple -threads or when there still are mocks in action. - -## Controlling How Much Information Google Mock Prints ## - -When Google Mock sees something that has the potential of being an -error (e.g. a mock function with no expectation is called, a.k.a. an -uninteresting call, which is allowed but perhaps you forgot to -explicitly ban the call), it prints some warning messages, including -the arguments of the function and the return value. Hopefully this -will remind you to take a look and see if there is indeed a problem. - -Sometimes you are confident that your tests are correct and may not -appreciate such friendly messages. Some other times, you are debugging -your tests or learning about the behavior of the code you are testing, -and wish you could observe every mock call that happens (including -argument values and the return value). Clearly, one size doesn't fit -all. - -You can control how much Google Mock tells you using the -`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string -with three possible values: - - * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. - * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. - * `error`: Google Mock will print errors only (least verbose). - -Alternatively, you can adjust the value of that flag from within your -tests like so: - -``` - ::testing::FLAGS_gmock_verbose = "error"; -``` - -Now, judiciously use the right flag to enable Google Mock serve you better! - -## Running Tests in Emacs ## - -If you build and run your tests in Emacs, the source file locations of -Google Mock and [Google Test](http://code.google.com/p/googletest/) -errors will be highlighted. Just press `` on one of them and -you'll be taken to the offending line. Or, you can just type `C-x `` -to jump to the next error. - -To make it even easier, you can add the following lines to your -`~/.emacs` file: - -``` -(global-set-key "\M-m" 'compile) ; m is for make -(global-set-key [M-down] 'next-error) -(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) -``` - -Then you can type `M-m` to start a build, or `M-up`/`M-down` to move -back and forth between errors. - -## Fusing Google Mock Source Files ## - -Google Mock's implementation consists of dozens of files (excluding -its own tests). Sometimes you may want them to be packaged up in -fewer files instead, such that you can easily copy them to a new -machine and start hacking there. For this we provide an experimental -Python script `fuse_gmock_files.py` in the `scripts/` directory -(starting with release 1.2.0). Assuming you have Python 2.4 or above -installed on your machine, just go to that directory and run -``` -python fuse_gmock_files.py OUTPUT_DIR -``` - -and you should see an `OUTPUT_DIR` directory being created with files -`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. -These three files contain everything you need to use Google Mock (and -Google Test). Just copy them to anywhere you want and you are ready -to write tests and use mocks. You can use the -[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests -against them. - -# Extending Google Mock # - -## Writing New Matchers Quickly ## - -The `MATCHER*` family of macros can be used to define custom matchers -easily. The syntax: - -``` -MATCHER(name, description_string_expression) { statements; } -``` - -will define a matcher with the given name that executes the -statements, which must return a `bool` to indicate if the match -succeeds. Inside the statements, you can refer to the value being -matched by `arg`, and refer to its type by `arg_type`. - -The description string is a `string`-typed expression that documents -what the matcher does, and is used to generate the failure message -when the match fails. It can (and should) reference the special -`bool` variable `negation`, and should evaluate to the description of -the matcher when `negation` is `false`, or that of the matcher's -negation when `negation` is `true`. - -For convenience, we allow the description string to be empty (`""`), -in which case Google Mock will use the sequence of words in the -matcher name as the description. - -For example: -``` -MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } -``` -allows you to write -``` - // Expects mock_foo.Bar(n) to be called where n is divisible by 7. - EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); -``` -or, -``` -using ::testing::Not; -... - EXPECT_THAT(some_expression, IsDivisibleBy7()); - EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); -``` -If the above assertions fail, they will print something like: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 -... - Value of: some_other_expression - Expected: not (is divisible by 7) - Actual: 21 -``` -where the descriptions `"is divisible by 7"` and `"not (is divisible -by 7)"` are automatically calculated from the matcher name -`IsDivisibleBy7`. - -As you may have noticed, the auto-generated descriptions (especially -those for the negation) may not be so great. You can always override -them with a string expression of your own: -``` -MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + - " divisible by 7") { - return (arg % 7) == 0; -} -``` - -Optionally, you can stream additional information to a hidden argument -named `result_listener` to explain the match result. For example, a -better definition of `IsDivisibleBy7` is: -``` -MATCHER(IsDivisibleBy7, "") { - if ((arg % 7) == 0) - return true; - - *result_listener << "the remainder is " << (arg % 7); - return false; -} -``` - -With this definition, the above assertion will give a better message: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 (the remainder is 6) -``` - -You should let `MatchAndExplain()` print _any additional information_ -that can help a user understand the match result. Note that it should -explain why the match succeeds in case of a success (unless it's -obvious) - this is useful when the matcher is used inside -`Not()`. There is no need to print the argument value itself, as -Google Mock already prints it for you. - -**Notes:** - - 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. - 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. - -## Writing New Parameterized Matchers Quickly ## - -Sometimes you'll want to define a matcher that has parameters. For that you -can use the macro: -``` -MATCHER_P(name, param_name, description_string) { statements; } -``` -where the description string can be either `""` or a string expression -that references `negation` and `param_name`. - -For example: -``` -MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -``` -will allow you to write: -``` - EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -``` -which may lead to this message (assuming `n` is 10): -``` - Value of: Blah("a") - Expected: has absolute value 10 - Actual: -9 -``` - -Note that both the matcher description and its parameter are -printed, making the message human-friendly. - -In the matcher definition body, you can write `foo_type` to -reference the type of a parameter named `foo`. For example, in the -body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write -`value_type` to refer to the type of `value`. - -Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to -`MATCHER_P10` to support multi-parameter matchers: -``` -MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } -``` - -Please note that the custom description string is for a particular -**instance** of the matcher, where the parameters have been bound to -actual values. Therefore usually you'll want the parameter values to -be part of the description. Google Mock lets you do that by -referencing the matcher parameters in the description string -expression. - -For example, -``` - using ::testing::PrintToString; - MATCHER_P2(InClosedRange, low, hi, - std::string(negation ? "isn't" : "is") + " in range [" + - PrintToString(low) + ", " + PrintToString(hi) + "]") { - return low <= arg && arg <= hi; - } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the message: -``` - Expected: is in range [4, 6] -``` - -If you specify `""` as the description, the failure message will -contain the sequence of words in the matcher name followed by the -parameter values printed as a tuple. For example, -``` - MATCHER_P2(InClosedRange, low, hi, "") { ... } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the text: -``` - Expected: in closed range (4, 6) -``` - -For the purpose of typing, you can view -``` -MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -``` -as shorthand for -``` -template -FooMatcherPk -Foo(p1_type p1, ..., pk_type pk) { ... } -``` - -When you write `Foo(v1, ..., vk)`, the compiler infers the types of -the parameters `v1`, ..., and `vk` for you. If you are not happy with -the result of the type inference, you can specify the types by -explicitly instantiating the template, as in `Foo(5, false)`. -As said earlier, you don't get to (or need to) specify -`arg_type` as that's determined by the context in which the matcher -is used. - -You can assign the result of expression `Foo(p1, ..., pk)` to a -variable of type `FooMatcherPk`. This can be -useful when composing matchers. Matchers that don't have a parameter -or have only one parameter have special types: you can assign `Foo()` -to a `FooMatcher`-typed variable, and assign `Foo(p)` to a -`FooMatcherP`-typed variable. - -While you can instantiate a matcher template with reference types, -passing the parameters by pointer usually makes your code more -readable. If, however, you still want to pass a parameter by -reference, be aware that in the failure message generated by the -matcher you will see the value of the referenced object but not its -address. - -You can overload matchers with different numbers of parameters: -``` -MATCHER_P(Blah, a, description_string_1) { ... } -MATCHER_P2(Blah, a, b, description_string_2) { ... } -``` - -While it's tempting to always use the `MATCHER*` macros when defining -a new matcher, you should also consider implementing -`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see -the recipes that follow), especially if you need to use the matcher a -lot. While these approaches require more work, they give you more -control on the types of the value being matched and the matcher -parameters, which in general leads to better compiler error messages -that pay off in the long run. They also allow overloading matchers -based on parameter types (as opposed to just based on the number of -parameters). - -## Writing New Monomorphic Matchers ## - -A matcher of argument type `T` implements -`::testing::MatcherInterface` and does two things: it tests whether a -value of type `T` matches the matcher, and can describe what kind of -values it matches. The latter ability is used for generating readable -error messages when expectations are violated. - -The interface looks like this: - -``` -class MatchResultListener { - public: - ... - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x); - - // Returns the underlying ostream. - ::std::ostream* stream(); -}; - -template -class MatcherInterface { - public: - virtual ~MatcherInterface(); - - // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Describes this matcher to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. - virtual void DescribeNegationTo(::std::ostream* os) const; -}; -``` - -If you need a custom matcher but `Truly()` is not a good option (for -example, you may not be happy with the way `Truly(predicate)` -describes itself, or you may want your matcher to be polymorphic as -`Eq(value)` is), you can define a matcher to do whatever you want in -two steps: first implement the matcher interface, and then define a -factory function to create a matcher instance. The second step is not -strictly needed but it makes the syntax of using the matcher nicer. - -For example, you can define a matcher to test whether an `int` is -divisible by 7 and then use it like this: -``` -using ::testing::MakeMatcher; -using ::testing::Matcher; -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { - return (n % 7) == 0; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is divisible by 7"; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "is not divisible by 7"; - } -}; - -inline Matcher DivisibleBy7() { - return MakeMatcher(new DivisibleBy7Matcher); -} -... - - EXPECT_CALL(foo, Bar(DivisibleBy7())); -``` - -You may improve the matcher message by streaming additional -information to the `listener` argument in `MatchAndExplain()`: - -``` -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, - MatchResultListener* listener) const { - const int remainder = n % 7; - if (remainder != 0) { - *listener << "the remainder is " << remainder; - } - return remainder == 0; - } - ... -}; -``` - -Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: -``` -Value of: x -Expected: is divisible by 7 - Actual: 23 (the remainder is 2) -``` - -## Writing New Polymorphic Matchers ## - -You've learned how to write your own matchers in the previous -recipe. Just one problem: a matcher created using `MakeMatcher()` only -works for one particular type of arguments. If you want a -_polymorphic_ matcher that works with arguments of several types (for -instance, `Eq(x)` can be used to match a `value` as long as `value` == -`x` compiles -- `value` and `x` don't have to share the same type), -you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit -involved. - -Fortunately, most of the time you can define a polymorphic matcher -easily with the help of `MakePolymorphicMatcher()`. Here's how you can -define `NotNull()` as an example: - -``` -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -using ::testing::NotNull; -using ::testing::PolymorphicMatcher; - -class NotNullMatcher { - public: - // To implement a polymorphic matcher, first define a COPYABLE class - // that has three members MatchAndExplain(), DescribeTo(), and - // DescribeNegationTo(), like the following. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, - MatchResultListener* /* listener */) const { - return p != NULL; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } -}; - -// To construct a polymorphic matcher, pass an instance of the class -// to MakePolymorphicMatcher(). Note the return type. -inline PolymorphicMatcher NotNull() { - return MakePolymorphicMatcher(NotNullMatcher()); -} -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -**Note:** Your polymorphic matcher class does **not** need to inherit from -`MatcherInterface` or any other class, and its methods do **not** need -to be virtual. - -Like in a monomorphic matcher, you may explain the match result by -streaming additional information to the `listener` argument in -`MatchAndExplain()`. - -## Writing New Cardinalities ## - -A cardinality is used in `Times()` to tell Google Mock how many times -you expect a call to occur. It doesn't have to be exact. For example, -you can say `AtLeast(5)` or `Between(2, 4)`. - -If the built-in set of cardinalities doesn't suit you, you are free to -define your own by implementing the following interface (in namespace -`testing`): - -``` -class CardinalityInterface { - public: - virtual ~CardinalityInterface(); - - // Returns true iff call_count calls will satisfy this cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; -}; -``` - -For example, to specify that a call must occur even number of times, -you can write - -``` -using ::testing::Cardinality; -using ::testing::CardinalityInterface; -using ::testing::MakeCardinality; - -class EvenNumberCardinality : public CardinalityInterface { - public: - virtual bool IsSatisfiedByCallCount(int call_count) const { - return (call_count % 2) == 0; - } - - virtual bool IsSaturatedByCallCount(int call_count) const { - return false; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "called even number of times"; - } -}; - -Cardinality EvenNumber() { - return MakeCardinality(new EvenNumberCardinality); -} -... - - EXPECT_CALL(foo, Bar(3)) - .Times(EvenNumber()); -``` - -## Writing New Actions Quickly ## - -If the built-in actions don't work for you, and you find it -inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` -family to quickly define a new action that can be used in your code as -if it's a built-in action. - -By writing -``` -ACTION(name) { statements; } -``` -in a namespace scope (i.e. not inside a class or function), you will -define an action with the given name that executes the statements. -The value returned by `statements` will be used as the return value of -the action. Inside the statements, you can refer to the K-th -(0-based) argument of the mock function as `argK`. For example: -``` -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -``` -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function -arguments. Rest assured that your code is type-safe though: -you'll get a compiler error if `*arg1` doesn't support the `++` -operator, or if the type of `++(*arg1)` isn't compatible with the mock -function's return type. - -Another example: -``` -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` -defines an action `Foo()` that invokes argument #2 (a function pointer) -with 5, calls function `Blah()`, sets the value pointed to by argument -#1 to 0, and returns argument #0. - -For more convenience and flexibility, you can also use the following -pre-defined symbols in the body of `ACTION`: - -| `argK_type` | The type of the K-th (0-based) argument of the mock function | -|:------------|:-------------------------------------------------------------| -| `args` | All arguments of the mock function as a tuple | -| `args_type` | The type of all arguments of the mock function as a tuple | -| `return_type` | The return type of the mock function | -| `function_type` | The type of the mock function | - -For example, when using an `ACTION` as a stub action for mock function: -``` -int DoSomething(bool flag, int* ptr); -``` -we have: -| **Pre-defined Symbol** | **Is Bound To** | -|:-----------------------|:----------------| -| `arg0` | the value of `flag` | -| `arg0_type` | the type `bool` | -| `arg1` | the value of `ptr` | -| `arg1_type` | the type `int*` | -| `args` | the tuple `(flag, ptr)` | -| `args_type` | the type `std::tr1::tuple` | -| `return_type` | the type `int` | -| `function_type` | the type `int(bool, int*)` | - -## Writing New Parameterized Actions Quickly ## - -Sometimes you'll want to parameterize an action you define. For that -we have another macro -``` -ACTION_P(name, param) { statements; } -``` - -For example, -``` -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -``` -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term _arguments_ for the values used to -invoke the mock function, and the term _parameters_ for the values -used to instantiate an action. - -Note that you don't need to provide the type of the parameter either. -Suppose the parameter is named `param`, you can also use the -Google-Mock-defined symbol `param_type` to refer to the type of the -parameter as inferred by the compiler. For example, in the body of -`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. - -Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support -multi-parameter actions. For example, -``` -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -``` -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the -number of parameters is 0. - -You can also easily define actions overloaded on the number of parameters: -``` -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -## Restricting the Type of an Argument or Parameter in an ACTION ## - -For maximum brevity and reusability, the `ACTION*` macros don't ask -you to provide the types of the mock function arguments and the action -parameters. Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. -There are several tricks to do that. For example: -``` -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` -where `StaticAssertTypeEq` is a compile-time assertion in Google Test -that verifies two types are the same. - -## Writing New Action Templates Quickly ## - -Sometimes you want to give an action explicit template parameters that -cannot be inferred from its value parameters. `ACTION_TEMPLATE()` -supports that and can be viewed as an extension to `ACTION()` and -`ACTION_P*()`. - -The syntax: -``` -ACTION_TEMPLATE(ActionName, - HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), - AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -``` - -defines an action template that takes _m_ explicit template parameters -and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is -between 0 and 10. `name_i` is the name of the i-th template -parameter, and `kind_i` specifies whether it's a `typename`, an -integral constant, or a template. `p_i` is the name of the i-th value -parameter. - -Example: -``` -// DuplicateArg(output) converts the k-th argument of the mock -// function to type T and copies it to *output. -ACTION_TEMPLATE(DuplicateArg, - // Note the comma between int and k: - HAS_2_TEMPLATE_PARAMS(int, k, typename, T), - AND_1_VALUE_PARAMS(output)) { - *output = T(std::tr1::get(args)); -} -``` - -To create an instance of an action template, write: -``` - ActionName(v1, ..., v_n) -``` -where the `t`s are the template arguments and the -`v`s are the value arguments. The value argument -types are inferred by the compiler. For example: -``` -using ::testing::_; -... - int n; - EXPECT_CALL(mock, Foo(_, _)) - .WillOnce(DuplicateArg<1, unsigned char>(&n)); -``` - -If you want to explicitly specify the value argument types, you can -provide additional template arguments: -``` - ActionName(v1, ..., v_n) -``` -where `u_i` is the desired type of `v_i`. - -`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the -number of value parameters, but not on the number of template -parameters. Without the restriction, the meaning of the following is -unclear: - -``` - OverloadedAction(x); -``` - -Are we using a single-template-parameter action where `bool` refers to -the type of `x`, or a two-template-parameter action where the compiler -is asked to infer the type of `x`? - -## Using the ACTION Object's Type ## - -If you are writing a function that returns an `ACTION` object, you'll -need to know its type. The type depends on the macro used to define -the action and the parameter types. The rule is relatively simple: -| **Given Definition** | **Expression** | **Has Type** | -|:---------------------|:---------------|:-------------| -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | -| ... | ... | ... | - -Note that we have to pick different suffixes (`Action`, `ActionP`, -`ActionP2`, and etc) for actions with different numbers of value -parameters, or the action definitions cannot be overloaded on the -number of them. - -## Writing New Monomorphic Actions ## - -While the `ACTION*` macros are very convenient, sometimes they are -inappropriate. For example, despite the tricks shown in the previous -recipes, they don't let you directly specify the types of the mock -function arguments and the action parameters, which in general leads -to unoptimized compiler error messages that can baffle unfamiliar -users. They also don't allow overloading actions based on parameter -types without jumping through some hoops. - -An alternative to the `ACTION*` macros is to implement -`::testing::ActionInterface`, where `F` is the type of the mock -function in which the action will be used. For example: - -``` -template class ActionInterface { - public: - virtual ~ActionInterface(); - - // Performs the action. Result is the return type of function type - // F, and ArgumentTuple is the tuple of arguments of F. - // - // For example, if F is int(bool, const string&), then Result would - // be int, and ArgumentTuple would be tr1::tuple. - virtual Result Perform(const ArgumentTuple& args) = 0; -}; - -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::MakeAction; - -typedef int IncrementMethod(int*); - -class IncrementArgumentAction : public ActionInterface { - public: - virtual int Perform(const tr1::tuple& args) { - int* p = tr1::get<0>(args); // Grabs the first argument. - return *p++; - } -}; - -Action IncrementArgument() { - return MakeAction(new IncrementArgumentAction); -} -... - - EXPECT_CALL(foo, Baz(_)) - .WillOnce(IncrementArgument()); - - int n = 5; - foo.Baz(&n); // Should return 5 and change n to 6. -``` - -## Writing New Polymorphic Actions ## - -The previous recipe showed you how to define your own action. This is -all good, except that you need to know the type of the function in -which the action will be used. Sometimes that can be a problem. For -example, if you want to use the action in functions with _different_ -types (e.g. like `Return()` and `SetArgPointee()`). - -If an action can be used in several types of mock functions, we say -it's _polymorphic_. The `MakePolymorphicAction()` function template -makes it easy to define such an action: - -``` -namespace testing { - -template -PolymorphicAction MakePolymorphicAction(const Impl& impl); - -} // namespace testing -``` - -As an example, let's define an action that returns the second argument -in the mock function's argument list. The first step is to define an -implementation class: - -``` -class ReturnSecondArgumentAction { - public: - template - Result Perform(const ArgumentTuple& args) const { - // To get the i-th (0-based) argument, use tr1::get(args). - return tr1::get<1>(args); - } -}; -``` - -This implementation class does _not_ need to inherit from any -particular class. What matters is that it must have a `Perform()` -method template. This method template takes the mock function's -arguments as a tuple in a **single** argument, and returns the result of -the action. It can be either `const` or not, but must be invokable -with exactly one template argument, which is the result type. In other -words, you must be able to call `Perform(args)` where `R` is the -mock function's return type and `args` is its arguments in a tuple. - -Next, we use `MakePolymorphicAction()` to turn an instance of the -implementation class into the polymorphic action we need. It will be -convenient to have a wrapper for this: - -``` -using ::testing::MakePolymorphicAction; -using ::testing::PolymorphicAction; - -PolymorphicAction ReturnSecondArgument() { - return MakePolymorphicAction(ReturnSecondArgumentAction()); -} -``` - -Now, you can use this polymorphic action the same way you use the -built-in ones: - -``` -using ::testing::_; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, int(bool flag, int n)); - MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(ReturnSecondArgument()); - EXPECT_CALL(foo, DoThat(_, _, _)) - .WillOnce(ReturnSecondArgument()); - ... - foo.DoThis(true, 5); // Will return 5. - foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". -``` - -## Teaching Google Mock How to Print Your Values ## - -When an uninteresting or unexpected call occurs, Google Mock prints the -argument values and the stack trace to help you debug. Assertion -macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in -question when the assertion fails. Google Mock and Google Test do this using -Google Test's user-extensible value printer. - -This printer knows how to print built-in C++ types, native arrays, STL -containers, and any type that supports the `<<` operator. For other -types, it prints the raw bytes in the value and hopes that you the -user can figure it out. -[Google Test's advanced guide](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) -explains how to extend the printer to do a better job at -printing your particular type than to dump the bytes. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_6/Documentation.md b/src/libtoast/gtest/googlemock/docs/v1_6/Documentation.md deleted file mode 100644 index dcc9156c2..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_6/Documentation.md +++ /dev/null @@ -1,12 +0,0 @@ -This page lists all documentation wiki pages for Google Mock **1.6** -- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** - - * [ForDummies](V1_6_ForDummies.md) -- start here if you are new to Google Mock. - * [CheatSheet](V1_6_CheatSheet.md) -- a quick reference. - * [CookBook](V1_6_CookBook.md) -- recipes for doing various tasks using Google Mock. - * [FrequentlyAskedQuestions](V1_6_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. - -To contribute code to Google Mock, read: - - * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. - * [Pump Manual](http://code.google.com/p/googletest/wiki/V1_6_PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_6/ForDummies.md b/src/libtoast/gtest/googlemock/docs/v1_6/ForDummies.md deleted file mode 100644 index 19ee63ab0..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_6/ForDummies.md +++ /dev/null @@ -1,439 +0,0 @@ - - -(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_6_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) - -# What Is Google C++ Mocking Framework? # -When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). - -**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: - - * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. - * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. - -If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. - -**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. - -Using Google Mock involves three basic steps: - - 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; - 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; - 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. - -# Why Google Mock? # -While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: - - * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. - * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. - * The knowledge you gained from using one mock doesn't transfer to the next. - -In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. - -Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: - - * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". - * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). - * Your tests are brittle as some resources they use are unreliable (e.g. the network). - * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. - * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. - * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. - -We encourage you to use Google Mock as: - - * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! - * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. - -# Getting Started # -Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. - -# A Case for Mock Turtles # -Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: - -``` -class Turtle { - ... - virtual ~Turtle() {} - virtual void PenUp() = 0; - virtual void PenDown() = 0; - virtual void Forward(int distance) = 0; - virtual void Turn(int degrees) = 0; - virtual void GoTo(int x, int y) = 0; - virtual int GetX() const = 0; - virtual int GetY() const = 0; -}; -``` - -(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) - -You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. - -Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. - -# Writing the Mock Class # -If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) - -## How to Define It ## -Using the `Turtle` interface as example, here are the simple steps you need to follow: - - 1. Derive a class `MockTurtle` from `Turtle`. - 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. - 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. - 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). - 1. Repeat until all virtual functions you want to mock are done. - -After the process, you should have something like: - -``` -#include "gmock/gmock.h" // Brings in Google Mock. -class MockTurtle : public Turtle { - public: - ... - MOCK_METHOD0(PenUp, void()); - MOCK_METHOD0(PenDown, void()); - MOCK_METHOD1(Forward, void(int distance)); - MOCK_METHOD1(Turn, void(int degrees)); - MOCK_METHOD2(GoTo, void(int x, int y)); - MOCK_CONST_METHOD0(GetX, int()); - MOCK_CONST_METHOD0(GetY, int()); -}; -``` - -You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. - -**Tip:** If even this is too much work for you, you'll find the -`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line -tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, -and it will print the definition of the mock class for you. Due to the -complexity of the C++ language, this script may not always work, but -it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). - -## Where to Put It ## -When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) - -So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. - -Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. - -# Using Mocks in Tests # -Once you have a mock class, using it is easy. The typical work flow is: - - 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). - 1. Create some mock objects. - 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). - 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. - 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. - -Here's an example: - -``` -#include "path/to/mock-turtle.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -using ::testing::AtLeast; // #1 - -TEST(PainterTest, CanDrawSomething) { - MockTurtle turtle; // #2 - EXPECT_CALL(turtle, PenDown()) // #3 - .Times(AtLeast(1)); - - Painter painter(&turtle); // #4 - - EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); -} // #5 - -int main(int argc, char** argv) { - // The following line must be executed to initialize Google Mock - // (and Google Test) before running the tests. - ::testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: - -``` -path/to/my_test.cc:119: Failure -Actual function call count doesn't match this expectation: -Actually: never called; -Expected: called at least once. -``` - -**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. - -**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. - -**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. - -This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. - -Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. - -## Using Google Mock with Any Testing Framework ## -If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or -[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: -``` -int main(int argc, char** argv) { - // The following line causes Google Mock to throw an exception on failure, - // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = true; - ::testing::InitGoogleMock(&argc, argv); - ... whatever your testing framework requires ... -} -``` - -This approach has a catch: it makes Google Mock throw an exception -from a mock object's destructor sometimes. With some compilers, this -sometimes causes the test program to crash. You'll still be able to -notice that the test has failed, but it's not a graceful failure. - -A better solution is to use Google Test's -[event listener API](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) -to report a test failure to your testing framework properly. You'll need to -implement the `OnTestPartResult()` method of the event listener interface, but it -should be straightforward. - -If this turns out to be too much work, we suggest that you stick with -Google Test, which works with Google Mock seamlessly (in fact, it is -technically part of Google Mock.). If there is a reason that you -cannot use Google Test, please let us know. - -# Setting Expectations # -The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." - -## General Syntax ## -In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: - -``` -EXPECT_CALL(mock_object, method(matchers)) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) - -The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. - -This syntax is designed to make an expectation read like English. For example, you can probably guess that - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .Times(5) - .WillOnce(Return(100)) - .WillOnce(Return(150)) - .WillRepeatedly(Return(200)); -``` - -says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). - -**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. - -## Matchers: What Arguments Do We Expect? ## -When a mock function takes arguments, we must specify what arguments we are expecting; for example: - -``` -// Expects the turtle to move forward by 100 units. -EXPECT_CALL(turtle, Forward(100)); -``` - -Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": - -``` -using ::testing::_; -... -// Expects the turtle to move forward. -EXPECT_CALL(turtle, Forward(_)); -``` - -`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. - -A list of built-in matchers can be found in the [CheatSheet](V1_6_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: - -``` -using ::testing::Ge;... -EXPECT_CALL(turtle, Forward(Ge(100))); -``` - -This checks that the turtle will be told to go forward by at least 100 units. - -## Cardinalities: How Many Times Will It Be Called? ## -The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. - -An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. - -We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_6_CheatSheet.md). - -The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: - - * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. - * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. - * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. - -**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? - -## Actions: What Should It Do? ## -Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. - -First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. - -Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillOnce(Return(300)); -``` - -This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillRepeatedly(Return(300)); -``` - -says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. - -Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). - -What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#Actions). - -**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: - -``` -int n = 100; -EXPECT_CALL(turtle, GetX()) -.Times(4) -.WillRepeatedly(Return(n++)); -``` - -Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_6_CookBook.md). - -Time for another quiz! What do you think the following means? - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) -.Times(4) -.WillOnce(Return(100)); -``` - -Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. - -## Using Multiple Expectations ## -So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. - -By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: - -``` -using ::testing::_;... -EXPECT_CALL(turtle, Forward(_)); // #1 -EXPECT_CALL(turtle, Forward(10)) // #2 - .Times(2); -``` - -If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. - -**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. - -## Ordered vs Unordered Calls ## -By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. - -Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: - -``` -using ::testing::InSequence;... -TEST(FooTest, DrawsLineSegment) { - ... - { - InSequence dummy; - - EXPECT_CALL(turtle, PenDown()); - EXPECT_CALL(turtle, Forward(100)); - EXPECT_CALL(turtle, PenUp()); - } - Foo(); -} -``` - -By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. - -In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. - -(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_6_CookBook.md).) - -## All Expectations Are Sticky (Unless Said Otherwise) ## -Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? - -After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): - -``` -using ::testing::_;... -EXPECT_CALL(turtle, GoTo(_, _)) // #1 - .Times(AnyNumber()); -EXPECT_CALL(turtle, GoTo(0, 0)) // #2 - .Times(2); -``` - -Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. - -This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). - -Simple? Let's see if you've really understood it: what does the following code say? - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)); -} -``` - -If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! - -One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); -} -``` - -And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: - -``` -using ::testing::InSequence; -using ::testing::Return; -... -{ - InSequence s; - - for (int i = 1; i <= n; i++) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); - } -} -``` - -By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). - -## Uninteresting Calls ## -A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. - -In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. - -# What Now? # -Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. - -Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_6_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_6/FrequentlyAskedQuestions.md b/src/libtoast/gtest/googlemock/docs/v1_6/FrequentlyAskedQuestions.md deleted file mode 100644 index f74715d2e..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_6/FrequentlyAskedQuestions.md +++ /dev/null @@ -1,628 +0,0 @@ - - -Please send your questions to the -[googlemock](http://groups.google.com/group/googlemock) discussion -group. If you need help with compiler errors, make sure you have -tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. - -## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## - -In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods). - -## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## - -After version 1.4.0 of Google Mock was released, we had an idea on how -to make it easier to write matchers that can generate informative -messages efficiently. We experimented with this idea and liked what -we saw. Therefore we decided to implement it. - -Unfortunately, this means that if you have defined your own matchers -by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, -your definitions will no longer compile. Matchers defined using the -`MATCHER*` family of macros are not affected. - -Sorry for the hassle if your matchers are affected. We believe it's -in everyone's long-term interest to make this change sooner than -later. Fortunately, it's usually not hard to migrate an existing -matcher to the new API. Here's what you need to do: - -If you wrote your matcher like this: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` - -you'll need to change it to: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` -(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second -argument of type `MatchResultListener*`.) - -If you were also using `ExplainMatchResultTo()` to improve the matcher -message: -``` -// Old matcher definition that doesn't work with the lastest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - - virtual void ExplainMatchResultTo(MyType value, - ::std::ostream* os) const { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Foo property is " << value.GetFoo(); - } - ... -}; -``` - -you should move the logic of `ExplainMatchResultTo()` into -`MatchAndExplain()`, using the `MatchResultListener` argument where -the `::std::ostream` was used: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Foo property is " << value.GetFoo(); - return value.GetFoo() > 5; - } - ... -}; -``` - -If your matcher is defined using `MakePolymorphicMatcher()`: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you should rename the `Matches()` method to `MatchAndExplain()` and -add a `MatchResultListener*` argument (the same as what you need to do -for matchers defined by implementing `MatcherInterface`): -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -If your polymorphic matcher uses `ExplainMatchResultTo()` for better -failure messages: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -void ExplainMatchResultTo(const MyGreatMatcher& matcher, - MyType value, - ::std::ostream* os) { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Bar property is " << value.GetBar(); -} -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you'll need to move the logic inside `ExplainMatchResultTo()` to -`MatchAndExplain()`: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Bar property is " << value.GetBar(); - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -For more information, you can read these -[two](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Monomorphic_Matchers) -[recipes](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Matchers) -from the cookbook. As always, you -are welcome to post questions on `googlemock@googlegroups.com` if you -need any help. - -## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## - -Google Mock works out of the box with Google Test. However, it's easy -to configure it to work with any testing framework of your choice. -[Here](http://code.google.com/p/googlemock/wiki/V1_6_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. - -## How am I supposed to make sense of these horrible template errors? ## - -If you are confused by the compiler errors gcc threw at you, -try consulting the _Google Mock Doctor_ tool first. What it does is to -scan stdin for gcc error messages, and spit out diagnoses on the -problems (we call them diseases) your code has. - -To "install", run command: -``` -alias gmd='/scripts/gmock_doctor.py' -``` - -To use it, do: -``` - 2>&1 | gmd -``` - -For example: -``` -make my_test 2>&1 | gmd -``` - -Or you can run `gmd` and copy-n-paste gcc's error messages to it. - -## Can I mock a variadic function? ## - -You cannot mock a variadic function (i.e. a function taking ellipsis -(`...`) arguments) directly in Google Mock. - -The problem is that in general, there is _no way_ for a mock object to -know how many arguments are passed to the variadic method, and what -the arguments' types are. Only the _author of the base class_ knows -the protocol, and we cannot look into his head. - -Therefore, to mock such a function, the _user_ must teach the mock -object how to figure out the number of arguments and their types. One -way to do it is to provide overloaded versions of the function. - -Ellipsis arguments are inherited from C and not really a C++ feature. -They are unsafe to use and don't work with arguments that have -constructors or destructors. Therefore we recommend to avoid them in -C++ as much as possible. - -## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## - -If you compile this using Microsoft Visual C++ 2005 SP1: -``` -class Foo { - ... - virtual void Bar(const int i) = 0; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Bar, void(const int i)); -}; -``` -You may get the following warning: -``` -warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier -``` - -This is a MSVC bug. The same code compiles fine with gcc ,for -example. If you use Visual C++ 2008 SP1, you would get the warning: -``` -warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers -``` - -In C++, if you _declare_ a function with a `const` parameter, the -`const` modifier is _ignored_. Therefore, the `Foo` base class above -is equivalent to: -``` -class Foo { - ... - virtual void Bar(int i) = 0; // int or const int? Makes no difference. -}; -``` - -In fact, you can _declare_ Bar() with an `int` parameter, and _define_ -it with a `const int` parameter. The compiler will still match them -up. - -Since making a parameter `const` is meaningless in the method -_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. -That should workaround the VC bug. - -Note that we are talking about the _top-level_ `const` modifier here. -If the function parameter is passed by pointer or reference, declaring -the _pointee_ or _referee_ as `const` is still meaningful. For -example, the following two declarations are _not_ equivalent: -``` -void Bar(int* p); // Neither p nor *p is const. -void Bar(const int* p); // p is not const, but *p is. -``` - -## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## - -We've noticed that when the `/clr` compiler flag is used, Visual C++ -uses 5~6 times as much memory when compiling a mock class. We suggest -to avoid `/clr` when compiling native C++ mocks. - -## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## - -You might want to run your test with -`--gmock_verbose=info`. This flag lets Google Mock print a trace -of every mock function call it receives. By studying the trace, -you'll gain insights on why the expectations you set are not met. - -## How can I assert that a function is NEVER called? ## - -``` -EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## - -When Google Mock detects a failure, it prints relevant information -(the mock function arguments, the state of relevant expectations, and -etc) to help the user debug. If another failure is detected, Google -Mock will do the same, including printing the state of relevant -expectations. - -Sometimes an expectation's state didn't change between two failures, -and you'll see the same description of the state twice. They are -however _not_ redundant, as they refer to _different points in time_. -The fact they are the same _is_ interesting information. - -## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## - -Does the class (hopefully a pure interface) you are mocking have a -virtual destructor? - -Whenever you derive from a base class, make sure its destructor is -virtual. Otherwise Bad Things will happen. Consider the following -code: - -``` -class Base { - public: - // Not virtual, but should be. - ~Base() { ... } - ... -}; - -class Derived : public Base { - public: - ... - private: - std::string value_; -}; - -... - Base* p = new Derived; - ... - delete p; // Surprise! ~Base() will be called, but ~Derived() will not - // - value_ is leaked. -``` - -By changing `~Base()` to virtual, `~Derived()` will be correctly -called when `delete p` is executed, and the heap checker -will be happy. - -## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## - -When people complain about this, often they are referring to code like: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. However, I have to write the expectations in the -// reverse order. This sucks big time!!! -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); -``` - -The problem is that they didn't pick the **best** way to express the test's -intent. - -By default, expectations don't have to be matched in _any_ particular -order. If you want them to match in a certain order, you need to be -explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's -easy to accidentally over-specify your tests, and we want to make it -harder to do so. - -There are two better ways to write the test spec. You could either -put the expectations in sequence: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. Using a sequence, we can write the expectations -// in their natural order. -{ - InSequence s; - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -} -``` - -or you can put the sequence of actions in the same expectation: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -``` - -Back to the original questions: why does Google Mock search the -expectations (and `ON_CALL`s) from back to front? Because this -allows a user to set up a mock's behavior for the common case early -(e.g. in the mock's constructor or the test fixture's set-up phase) -and customize it with more specific rules later. If Google Mock -searches from front to back, this very useful pattern won't be -possible. - -## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## - -When choosing between being neat and being safe, we lean toward the -latter. So the answer is that we think it's better to show the -warning. - -Often people write `ON_CALL`s in the mock object's -constructor or `SetUp()`, as the default behavior rarely changes from -test to test. Then in the test body they set the expectations, which -are often different for each test. Having an `ON_CALL` in the set-up -part of a test doesn't mean that the calls are expected. If there's -no `EXPECT_CALL` and the method is called, it's possibly an error. If -we quietly let the call go through without notifying the user, bugs -may creep in unnoticed. - -If, however, you are sure that the calls are OK, you can write - -``` -EXPECT_CALL(foo, Bar(_)) - .WillRepeatedly(...); -``` - -instead of - -``` -ON_CALL(foo, Bar(_)) - .WillByDefault(...); -``` - -This tells Google Mock that you do expect the calls and no warning should be -printed. - -Also, you can control the verbosity using the `--gmock_verbose` flag. -If you find the output too noisy when debugging, just choose a less -verbose level. - -## How can I delete the mock function's argument in an action? ## - -If you find yourself needing to perform some action that's not -supported by Google Mock directly, remember that you can define your own -actions using -[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Actions) or -[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Actions), -or you can write a stub function and invoke it using -[Invoke()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Functions_Methods_Functors). - -## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## - -What?! I think it's beautiful. :-) - -While which syntax looks more natural is a subjective matter to some -extent, Google Mock's syntax was chosen for several practical advantages it -has. - -Try to mock a function that takes a map as an argument: -``` -virtual int GetSize(const map& m); -``` - -Using the proposed syntax, it would be: -``` -MOCK_METHOD1(GetSize, int, const map& m); -``` - -Guess what? You'll get a compiler error as the compiler thinks that -`const map& m` are **two**, not one, arguments. To work -around this you can use `typedef` to give the map type a name, but -that gets in the way of your work. Google Mock's syntax avoids this -problem as the function's argument types are protected inside a pair -of parentheses: -``` -// This compiles fine. -MOCK_METHOD1(GetSize, int(const map& m)); -``` - -You still need a `typedef` if the return type contains an unprotected -comma, but that's much rarer. - -Other advantages include: - 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. - 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. - 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! - -## My code calls a static/global function. Can I mock it? ## - -You can, but you need to make some changes. - -In general, if you find yourself needing to mock a static function, -it's a sign that your modules are too tightly coupled (and less -flexible, less reusable, less testable, etc). You are probably better -off defining a small interface and call the function through that -interface, which then can be easily mocked. It's a bit of work -initially, but usually pays for itself quickly. - -This Google Testing Blog -[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) -says it excellently. Check it out. - -## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## - -I know it's not a question, but you get an answer for free any way. :-) - -With Google Mock, you can create mocks in C++ easily. And people might be -tempted to use them everywhere. Sometimes they work great, and -sometimes you may find them, well, a pain to use. So, what's wrong in -the latter case? - -When you write a test without using mocks, you exercise the code and -assert that it returns the correct value or that the system is in an -expected state. This is sometimes called "state-based testing". - -Mocks are great for what some call "interaction-based" testing: -instead of checking the system state at the very end, mock objects -verify that they are invoked the right way and report an error as soon -as it arises, giving you a handle on the precise context in which the -error was triggered. This is often more effective and economical to -do than state-based testing. - -If you are doing state-based testing and using a test double just to -simulate the real object, you are probably better off using a fake. -Using a mock in this case causes pain, as it's not a strong point for -mocks to perform complex actions. If you experience this and think -that mocks suck, you are just not using the right tool for your -problem. Or, you might be trying to solve the wrong problem. :-) - -## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## - -By all means, NO! It's just an FYI. - -What it means is that you have a mock function, you haven't set any -expectations on it (by Google Mock's rule this means that you are not -interested in calls to this function and therefore it can be called -any number of times), and it is called. That's OK - you didn't say -it's not OK to call the function! - -What if you actually meant to disallow this function to be called, but -forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While -one can argue that it's the user's fault, Google Mock tries to be nice and -prints you a note. - -So, when you see the message and believe that there shouldn't be any -uninteresting calls, you should investigate what's going on. To make -your life easier, Google Mock prints the function name and arguments -when an uninteresting call is encountered. - -## I want to define a custom action. Should I use Invoke() or implement the action interface? ## - -Either way is fine - you want to choose the one that's more convenient -for your circumstance. - -Usually, if your action is for a particular function type, defining it -using `Invoke()` should be easier; if your action can be used in -functions of different types (e.g. if you are defining -`Return(value)`), `MakePolymorphicAction()` is -easiest. Sometimes you want precise control on what types of -functions the action can be used in, and implementing -`ActionInterface` is the way to go here. See the implementation of -`Return()` in `include/gmock/gmock-actions.h` for an example. - -## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## - -You got this error as Google Mock has no idea what value it should return -when the mock method is called. `SetArgPointee()` says what the -side effect is, but doesn't say what the return value should be. You -need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. - -See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Side_Effects) for more details and an example. - - -## My question is not in your FAQ! ## - -If you cannot find the answer to your question in this FAQ, there are -some other resources you can use: - - 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), - 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), - 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). - -Please note that creating an issue in the -[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ -a good way to get your answer, as it is monitored infrequently by a -very small number of people. - -When asking a question, it's helpful to provide as much of the -following information as possible (people cannot help you if there's -not enough information in your question): - - * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), - * your operating system, - * the name and version of your compiler, - * the complete command line flags you give to your compiler, - * the complete compiler error messages (if the question is about compilation), - * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_7/CheatSheet.md b/src/libtoast/gtest/googlemock/docs/v1_7/CheatSheet.md deleted file mode 100644 index db421e51b..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_7/CheatSheet.md +++ /dev/null @@ -1,556 +0,0 @@ - - -# Defining a Mock Class # - -## Mocking a Normal Class ## - -Given -``` -class Foo { - ... - virtual ~Foo(); - virtual int GetSize() const = 0; - virtual string Describe(const char* name) = 0; - virtual string Describe(int type) = 0; - virtual bool Process(Bar elem, int count) = 0; -}; -``` -(note that `~Foo()` **must** be virtual) we can define its mock as -``` -#include "gmock/gmock.h" - -class MockFoo : public Foo { - MOCK_CONST_METHOD0(GetSize, int()); - MOCK_METHOD1(Describe, string(const char* name)); - MOCK_METHOD1(Describe, string(int type)); - MOCK_METHOD2(Process, bool(Bar elem, int count)); -}; -``` - -To create a "nice" mock object which ignores all uninteresting calls, -or a "strict" mock object, which treats them as failures: -``` -NiceMock nice_foo; // The type is a subclass of MockFoo. -StrictMock strict_foo; // The type is a subclass of MockFoo. -``` - -## Mocking a Class Template ## - -To mock -``` -template -class StackInterface { - public: - ... - virtual ~StackInterface(); - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; -``` -(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: -``` -template -class MockStack : public StackInterface { - public: - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Specifying Calling Conventions for Mock Functions ## - -If your mock function doesn't use the default calling convention, you -can specify it by appending `_WITH_CALLTYPE` to any of the macros -described in the previous two sections and supplying the calling -convention as the first argument to the macro. For example, -``` - MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); - MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); -``` -where `STDMETHODCALLTYPE` is defined by `` on Windows. - -# Using Mocks in Tests # - -The typical flow is: - 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. - 1. Create the mock objects. - 1. Optionally, set the default actions of the mock objects. - 1. Set your expectations on the mock objects (How will they be called? What wil they do?). - 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. - 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. - -Here is an example: -``` -using ::testing::Return; // #1 - -TEST(BarTest, DoesThis) { - MockFoo foo; // #2 - - ON_CALL(foo, GetSize()) // #3 - .WillByDefault(Return(1)); - // ... other default actions ... - - EXPECT_CALL(foo, Describe(5)) // #4 - .Times(3) - .WillRepeatedly(Return("Category 5")); - // ... other expectations ... - - EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 -} // #6 -``` - -# Setting Default Actions # - -Google Mock has a **built-in default action** for any function that -returns `void`, `bool`, a numeric value, or a pointer. - -To customize the default action for functions with return type `T` globally: -``` -using ::testing::DefaultValue; - -DefaultValue::Set(value); // Sets the default value to be returned. -// ... use the mocks ... -DefaultValue::Clear(); // Resets the default value. -``` - -To customize the default action for a particular method, use `ON_CALL()`: -``` -ON_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .WillByDefault(action); -``` - -# Setting Expectations # - -`EXPECT_CALL()` sets **expectations** on a mock method (How will it be -called? What will it do?): -``` -EXPECT_CALL(mock_object, method(matchers)) - .With(multi_argument_matcher) ? - .Times(cardinality) ? - .InSequence(sequences) * - .After(expectations) * - .WillOnce(action) * - .WillRepeatedly(action) ? - .RetiresOnSaturation(); ? -``` - -If `Times()` is omitted, the cardinality is assumed to be: - - * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; - * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or - * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. - -A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. - -# Matchers # - -A **matcher** matches a _single_ argument. You can use it inside -`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value -directly: - -| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | -|:------------------------------|:----------------------------------------| -| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | - -Built-in matchers (where `argument` is the function argument) are -divided into several categories: - -## Wildcard ## -|`_`|`argument` can be any value of the correct type.| -|:--|:-----------------------------------------------| -|`A()` or `An()`|`argument` can be any value of type `type`. | - -## Generic Comparison ## - -|`Eq(value)` or `value`|`argument == value`| -|:---------------------|:------------------| -|`Ge(value)` |`argument >= value`| -|`Gt(value)` |`argument > value` | -|`Le(value)` |`argument <= value`| -|`Lt(value)` |`argument < value` | -|`Ne(value)` |`argument != value`| -|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| -|`NotNull()` |`argument` is a non-null pointer (raw or smart).| -|`Ref(variable)` |`argument` is a reference to `variable`.| -|`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| - -Except `Ref()`, these matchers make a _copy_ of `value` in case it's -modified or destructed later. If the compiler complains that `value` -doesn't have a public copy constructor, try wrap it in `ByRef()`, -e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure -`non_copyable_value` is not changed afterwards, or the meaning of your -matcher will be changed. - -## Floating-Point Matchers ## - -|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| -|:-------------------|:----------------------------------------------------------------------------------------------| -|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | -|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | -|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | - -The above matchers use ULP-based comparison (the same as used in -[Google Test](http://code.google.com/p/googletest/)). They -automatically pick a reasonable error bound based on the absolute -value of the expected value. `DoubleEq()` and `FloatEq()` conform to -the IEEE standard, which requires comparing two NaNs for equality to -return false. The `NanSensitive*` version instead treats two NaNs as -equal, which is often what a user wants. - -|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| -|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| -|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | -|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | -|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | - -## String Matchers ## - -The `argument` can be either a C string or a C++ string object: - -|`ContainsRegex(string)`|`argument` matches the given regular expression.| -|:----------------------|:-----------------------------------------------| -|`EndsWith(suffix)` |`argument` ends with string `suffix`. | -|`HasSubstr(string)` |`argument` contains `string` as a sub-string. | -|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| -|`StartsWith(prefix)` |`argument` starts with string `prefix`. | -|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | -|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| -|`StrEq(string)` |`argument` is equal to `string`. | -|`StrNe(string)` |`argument` is not equal to `string`. | - -`ContainsRegex()` and `MatchesRegex()` use the regular expression -syntax defined -[here](http://code.google.com/p/googletest/wiki/AdvancedGuide#Regular_Expression_Syntax). -`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide -strings as well. - -## Container Matchers ## - -Most STL-style containers support `==`, so you can use -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. If you want to write the elements in-line, -match them more flexibly, or get more informative messages, you can use: - -| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | -|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| -| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | -| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | -| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | -| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | -| `IsEmpty()` | `argument` is an empty container (`container.empty()`). | -| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | -| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | -| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | -| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | -| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | -| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | - -Notes: - - * These matchers can also match: - 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and - 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). - * The array being matched may be multi-dimensional (i.e. its elements can be arrays). - * `m` in `Pointwise(m, ...)` should be a matcher for `std::tr1::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: - -``` -using ::std::tr1::get; -MATCHER(FooEq, "") { - return get<0>(arg).Equals(get<1>(arg)); -} -... -EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); -``` - -## Member Matchers ## - -|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| -|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| -|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| -|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | -|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| - -## Matching the Result of a Function or Functor ## - -|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| -|:---------------|:---------------------------------------------------------------------| - -## Pointer Matchers ## - -|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| -|:-----------|:-----------------------------------------------------------------------------------------------| - -## Multiargument Matchers ## - -Technically, all matchers match a _single_ value. A "multi-argument" -matcher is just one that matches a _tuple_. The following matchers can -be used to match a tuple `(x, y)`: - -|`Eq()`|`x == y`| -|:-----|:-------| -|`Ge()`|`x >= y`| -|`Gt()`|`x > y` | -|`Le()`|`x <= y`| -|`Lt()`|`x < y` | -|`Ne()`|`x != y`| - -You can use the following selectors to pick a subset of the arguments -(or reorder them) to participate in the matching: - -|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| -|:-----------|:-------------------------------------------------------------------| -|`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| - -## Composite Matchers ## - -You can make a matcher from one or more other matchers: - -|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| -|:-----------------------|:---------------------------------------------------| -|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| -|`Not(m)` |`argument` doesn't match matcher `m`. | - -## Adapters for Matchers ## - -|`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| -|:------------------|:--------------------------------------| -|`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | -|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| - -## Matchers as Predicates ## - -|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| -|:------------------|:---------------------------------------------------------------------------------------------| -|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | -|`Value(value, m)` |evaluates to `true` if `value` matches `m`. | - -## Defining Matchers ## - -| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | -|:-------------------------------------------------|:------------------------------------------------------| -| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | - -**Notes:** - - 1. The `MATCHER*` macros cannot be used inside a function or class. - 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). - 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. - -## Matchers as Test Assertions ## - -|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| -|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| -|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | - -# Actions # - -**Actions** specify what a mock function should do when invoked. - -## Returning a Value ## - -|`Return()`|Return from a `void` mock function.| -|:---------|:----------------------------------| -|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| -|`ReturnArg()`|Return the `N`-th (0-based) argument.| -|`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| -|`ReturnNull()`|Return a null pointer. | -|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| -|`ReturnRef(variable)`|Return a reference to `variable`. | -|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| - -## Side Effects ## - -|`Assign(&variable, value)`|Assign `value` to variable.| -|:-------------------------|:--------------------------| -| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | -| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | -| `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | -|`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| -|`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| -|`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| -|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| -|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| - -## Using a Function or a Functor as an Action ## - -|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| -|:----------|:-----------------------------------------------------------------------------------------------------------------| -|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | -|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | -|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | -|`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| - -The return value of the invoked function is used as the return value -of the action. - -When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: -``` - double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } - ... - EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); -``` - -In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, -``` - InvokeArgument<2>(5, string("Hi"), ByRef(foo)) -``` -calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. - -## Default Action ## - -|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| -|:------------|:--------------------------------------------------------------------| - -**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. - -## Composite Actions ## - -|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | -|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| -|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | -|`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | -|`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | -|`WithoutArgs(a)` |Perform action `a` without any arguments. | - -## Defining Actions ## - -| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | -|:--------------------------------------|:---------------------------------------------------------------------------------------| -| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | -| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | - -The `ACTION*` macros cannot be used inside a function or class. - -# Cardinalities # - -These are used in `Times()` to specify how many times a mock function will be called: - -|`AnyNumber()`|The function can be called any number of times.| -|:------------|:----------------------------------------------| -|`AtLeast(n)` |The call is expected at least `n` times. | -|`AtMost(n)` |The call is expected at most `n` times. | -|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| -|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| - -# Expectation Order # - -By default, the expectations can be matched in _any_ order. If some -or all expectations must be matched in a given order, there are two -ways to specify it. They can be used either independently or -together. - -## The After Clause ## - -``` -using ::testing::Expectation; -... -Expectation init_x = EXPECT_CALL(foo, InitX()); -Expectation init_y = EXPECT_CALL(foo, InitY()); -EXPECT_CALL(foo, Bar()) - .After(init_x, init_y); -``` -says that `Bar()` can be called only after both `InitX()` and -`InitY()` have been called. - -If you don't know how many pre-requisites an expectation has when you -write it, you can use an `ExpectationSet` to collect them: - -``` -using ::testing::ExpectationSet; -... -ExpectationSet all_inits; -for (int i = 0; i < element_count; i++) { - all_inits += EXPECT_CALL(foo, InitElement(i)); -} -EXPECT_CALL(foo, Bar()) - .After(all_inits); -``` -says that `Bar()` can be called only after all elements have been -initialized (but we don't care about which elements get initialized -before the others). - -Modifying an `ExpectationSet` after using it in an `.After()` doesn't -affect the meaning of the `.After()`. - -## Sequences ## - -When you have a long chain of sequential expectations, it's easier to -specify the order using **sequences**, which don't require you to given -each expectation in the chain a different name. All expected
-calls
in the same sequence must occur in the order they are -specified. - -``` -using ::testing::Sequence; -Sequence s1, s2; -... -EXPECT_CALL(foo, Reset()) - .InSequence(s1, s2) - .WillOnce(Return(true)); -EXPECT_CALL(foo, GetSize()) - .InSequence(s1) - .WillOnce(Return(1)); -EXPECT_CALL(foo, Describe(A())) - .InSequence(s2) - .WillOnce(Return("dummy")); -``` -says that `Reset()` must be called before _both_ `GetSize()` _and_ -`Describe()`, and the latter two can occur in any order. - -To put many expectations in a sequence conveniently: -``` -using ::testing::InSequence; -{ - InSequence dummy; - - EXPECT_CALL(...)...; - EXPECT_CALL(...)...; - ... - EXPECT_CALL(...)...; -} -``` -says that all expected calls in the scope of `dummy` must occur in -strict order. The name `dummy` is irrelevant.) - -# Verifying and Resetting a Mock # - -Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: -``` -using ::testing::Mock; -... -// Verifies and removes the expectations on mock_obj; -// returns true iff successful. -Mock::VerifyAndClearExpectations(&mock_obj); -... -// Verifies and removes the expectations on mock_obj; -// also removes the default actions set by ON_CALL(); -// returns true iff successful. -Mock::VerifyAndClear(&mock_obj); -``` - -You can also tell Google Mock that a mock object can be leaked and doesn't -need to be verified: -``` -Mock::AllowLeak(&mock_obj); -``` - -# Mock Classes # - -Google Mock defines a convenient mock class template -``` -class MockFunction { - public: - MOCK_METHODn(Call, R(A1, ..., An)); -}; -``` -See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Check_Points) for one application of it. - -# Flags # - -| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | -|:-------------------------------|:----------------------------------------------| -| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_7/CookBook.md b/src/libtoast/gtest/googlemock/docs/v1_7/CookBook.md deleted file mode 100644 index 419a00107..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_7/CookBook.md +++ /dev/null @@ -1,3432 +0,0 @@ - - -You can find recipes for using Google Mock here. If you haven't yet, -please read the [ForDummies](V1_7_ForDummies.md) document first to make sure you understand -the basics. - -**Note:** Google Mock lives in the `testing` name space. For -readability, it is recommended to write `using ::testing::Foo;` once in -your file before using the name `Foo` defined by Google Mock. We omit -such `using` statements in this page for brevity, but you should do it -in your own code. - -# Creating Mock Classes # - -## Mocking Private or Protected Methods ## - -You must always put a mock method definition (`MOCK_METHOD*`) in a -`public:` section of the mock class, regardless of the method being -mocked being `public`, `protected`, or `private` in the base class. -This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function -from outside of the mock class. (Yes, C++ allows a subclass to change -the access level of a virtual function in the base class.) Example: - -``` -class Foo { - public: - ... - virtual bool Transform(Gadget* g) = 0; - - protected: - virtual void Resume(); - - private: - virtual int GetTimeOut(); -}; - -class MockFoo : public Foo { - public: - ... - MOCK_METHOD1(Transform, bool(Gadget* g)); - - // The following must be in the public section, even though the - // methods are protected or private in the base class. - MOCK_METHOD0(Resume, void()); - MOCK_METHOD0(GetTimeOut, int()); -}; -``` - -## Mocking Overloaded Methods ## - -You can mock overloaded functions as usual. No special attention is required: - -``` -class Foo { - ... - - // Must be virtual as we'll inherit from Foo. - virtual ~Foo(); - - // Overloaded on the types and/or numbers of arguments. - virtual int Add(Element x); - virtual int Add(int times, Element x); - - // Overloaded on the const-ness of this object. - virtual Bar& GetBar(); - virtual const Bar& GetBar() const; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Add, int(Element x)); - MOCK_METHOD2(Add, int(int times, Element x); - - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -``` - -**Note:** if you don't mock all versions of the overloaded method, the -compiler will give you a warning about some methods in the base class -being hidden. To fix that, use `using` to bring them in scope: - -``` -class MockFoo : public Foo { - ... - using Foo::Add; - MOCK_METHOD1(Add, int(Element x)); - // We don't want to mock int Add(int times, Element x); - ... -}; -``` - -## Mocking Class Templates ## - -To mock a class template, append `_T` to the `MOCK_*` macros: - -``` -template -class StackInterface { - ... - // Must be virtual as we'll inherit from StackInterface. - virtual ~StackInterface(); - - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; - -template -class MockStack : public StackInterface { - ... - MOCK_CONST_METHOD0_T(GetSize, int()); - MOCK_METHOD1_T(Push, void(const Elem& x)); -}; -``` - -## Mocking Nonvirtual Methods ## - -Google Mock can mock non-virtual functions to be used in what we call _hi-perf -dependency injection_. - -In this case, instead of sharing a common base class with the real -class, your mock class will be _unrelated_ to the real class, but -contain methods with the same signatures. The syntax for mocking -non-virtual methods is the _same_ as mocking virtual methods: - -``` -// A simple packet stream class. None of its members is virtual. -class ConcretePacketStream { - public: - void AppendPacket(Packet* new_packet); - const Packet* GetPacket(size_t packet_number) const; - size_t NumberOfPackets() const; - ... -}; - -// A mock packet stream class. It inherits from no other, but defines -// GetPacket() and NumberOfPackets(). -class MockPacketStream { - public: - MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); - MOCK_CONST_METHOD0(NumberOfPackets, size_t()); - ... -}; -``` - -Note that the mock class doesn't define `AppendPacket()`, unlike the -real class. That's fine as long as the test doesn't need to call it. - -Next, you need a way to say that you want to use -`ConcretePacketStream` in production code, and use `MockPacketStream` -in tests. Since the functions are not virtual and the two classes are -unrelated, you must specify your choice at _compile time_ (as opposed -to run time). - -One way to do it is to templatize your code that needs to use a packet -stream. More specifically, you will give your code a template type -argument for the type of the packet stream. In production, you will -instantiate your template with `ConcretePacketStream` as the type -argument. In tests, you will instantiate the same template with -`MockPacketStream`. For example, you may write: - -``` -template -void CreateConnection(PacketStream* stream) { ... } - -template -class PacketReader { - public: - void ReadPackets(PacketStream* stream, size_t packet_num); -}; -``` - -Then you can use `CreateConnection()` and -`PacketReader` in production code, and use -`CreateConnection()` and -`PacketReader` in tests. - -``` - MockPacketStream mock_stream; - EXPECT_CALL(mock_stream, ...)...; - .. set more expectations on mock_stream ... - PacketReader reader(&mock_stream); - ... exercise reader ... -``` - -## Mocking Free Functions ## - -It's possible to use Google Mock to mock a free function (i.e. a -C-style function or a static method). You just need to rewrite your -code to use an interface (abstract class). - -Instead of calling a free function (say, `OpenFile`) directly, -introduce an interface for it and have a concrete subclass that calls -the free function: - -``` -class FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) = 0; -}; - -class File : public FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) { - return OpenFile(path, mode); - } -}; -``` - -Your code should talk to `FileInterface` to open a file. Now it's -easy to mock out the function. - -This may seem much hassle, but in practice you often have multiple -related functions that you can put in the same interface, so the -per-function syntactic overhead will be much lower. - -If you are concerned about the performance overhead incurred by -virtual functions, and profiling confirms your concern, you can -combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). - -## The Nice, the Strict, and the Naggy ## - -If a mock method has no `EXPECT_CALL` spec but is called, Google Mock -will print a warning about the "uninteresting call". The rationale is: - - * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. - * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. - -However, sometimes you may want to suppress all "uninteresting call" -warnings, while sometimes you may want the opposite, i.e. to treat all -of them as errors. Google Mock lets you make the decision on a -per-mock-object basis. - -Suppose your test uses a mock class `MockFoo`: - -``` -TEST(...) { - MockFoo mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -If a method of `mock_foo` other than `DoThis()` is called, it will be -reported by Google Mock as a warning. However, if you rewrite your -test to use `NiceMock` instead, the warning will be gone, -resulting in a cleaner test output: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -`NiceMock` is a subclass of `MockFoo`, so it can be used -wherever `MockFoo` is accepted. - -It also works if `MockFoo`'s constructor takes some arguments, as -`NiceMock` "inherits" `MockFoo`'s constructors: - -``` -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -The usage of `StrictMock` is similar, except that it makes all -uninteresting calls failures: - -``` -using ::testing::StrictMock; - -TEST(...) { - StrictMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... - - // The test will fail if a method of mock_foo other than DoThis() - // is called. -} -``` - -There are some caveats though (I don't like them just as much as the -next guy, but sadly they are side effects of C++'s limitations): - - 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. - 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). - 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) - -Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. - -## Simplifying the Interface without Breaking Existing Code ## - -Sometimes a method has a long list of arguments that is mostly -uninteresting. For example, - -``` -class LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, - const char* message, size_t message_len) = 0; -}; -``` - -This method's argument list is lengthy and hard to work with (let's -say that the `message` argument is not even 0-terminated). If we mock -it as is, using the mock will be awkward. If, however, we try to -simplify this interface, we'll need to fix all clients depending on -it, which is often infeasible. - -The trick is to re-dispatch the method in the mock class: - -``` -class ScopedMockLog : public LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const tm* tm_time, - const char* message, size_t message_len) { - // We are only interested in the log severity, full file name, and - // log message. - Log(severity, full_filename, std::string(message, message_len)); - } - - // Implements the mock method: - // - // void Log(LogSeverity severity, - // const string& file_path, - // const string& message); - MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, - const string& message)); -}; -``` - -By defining a new mock method with a trimmed argument list, we make -the mock class much more user-friendly. - -## Alternative to Mocking Concrete Classes ## - -Often you may find yourself using classes that don't implement -interfaces. In order to test your code that uses such a class (let's -call it `Concrete`), you may be tempted to make the methods of -`Concrete` virtual and then mock it. - -Try not to do that. - -Making a non-virtual function virtual is a big decision. It creates an -extension point where subclasses can tweak your class' behavior. This -weakens your control on the class because now it's harder to maintain -the class' invariants. You should make a function virtual only when -there is a valid reason for a subclass to override it. - -Mocking concrete classes directly is problematic as it creates a tight -coupling between the class and the tests - any small change in the -class may invalidate your tests and make test maintenance a pain. - -To avoid such problems, many programmers have been practicing "coding -to interfaces": instead of talking to the `Concrete` class, your code -would define an interface and talk to it. Then you implement that -interface as an adaptor on top of `Concrete`. In tests, you can easily -mock that interface to observe how your code is doing. - -This technique incurs some overhead: - - * You pay the cost of virtual function calls (usually not a problem). - * There is more abstraction for the programmers to learn. - -However, it can also bring significant benefits in addition to better -testability: - - * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. - * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. - -Some people worry that if everyone is practicing this technique, they -will end up writing lots of redundant code. This concern is totally -understandable. However, there are two reasons why it may not be the -case: - - * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. - * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. - -You need to weigh the pros and cons carefully for your particular -problem, but I'd like to assure you that the Java community has been -practicing this for a long time and it's a proven effective technique -applicable in a wide variety of situations. :-) - -## Delegating Calls to a Fake ## - -Some times you have a non-trivial fake implementation of an -interface. For example: - -``` -class Foo { - public: - virtual ~Foo() {} - virtual char DoThis(int n) = 0; - virtual void DoThat(const char* s, int* p) = 0; -}; - -class FakeFoo : public Foo { - public: - virtual char DoThis(int n) { - return (n > 0) ? '+' : - (n < 0) ? '-' : '0'; - } - - virtual void DoThat(const char* s, int* p) { - *p = strlen(s); - } -}; -``` - -Now you want to mock this interface such that you can set expectations -on it. However, you also want to use `FakeFoo` for the default -behavior, as duplicating it in the mock object is, well, a lot of -work. - -When you define the mock class using Google Mock, you can have it -delegate its default action to a fake class you already have, using -this pattern: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - // Normal mock method definitions using Google Mock. - MOCK_METHOD1(DoThis, char(int n)); - MOCK_METHOD2(DoThat, void(const char* s, int* p)); - - // Delegates the default actions of the methods to a FakeFoo object. - // This must be called *before* the custom ON_CALL() statements. - void DelegateToFake() { - ON_CALL(*this, DoThis(_)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); - ON_CALL(*this, DoThat(_, _)) - .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); - } - private: - FakeFoo fake_; // Keeps an instance of the fake in the mock. -}; -``` - -With that, you can use `MockFoo` in your tests as usual. Just remember -that if you don't explicitly set an action in an `ON_CALL()` or -`EXPECT_CALL()`, the fake will be called upon to do it: - -``` -using ::testing::_; - -TEST(AbcTest, Xyz) { - MockFoo foo; - foo.DelegateToFake(); // Enables the fake for delegation. - - // Put your ON_CALL(foo, ...)s here, if any. - - // No action specified, meaning to use the default action. - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(foo, DoThat(_, _)); - - int n = 0; - EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. - foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. - EXPECT_EQ(2, n); -} -``` - -**Some tips:** - - * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. - * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. - * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). - * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. - -Regarding the tip on mixing a mock and a fake, here's an example on -why it may be a bad sign: Suppose you have a class `System` for -low-level system operations. In particular, it does file and I/O -operations. And suppose you want to test how your code uses `System` -to do I/O, and you just want the file operations to work normally. If -you mock out the entire `System` class, you'll have to provide a fake -implementation for the file operation part, which suggests that -`System` is taking on too many roles. - -Instead, you can define a `FileOps` interface and an `IOOps` interface -and split `System`'s functionalities into the two. Then you can mock -`IOOps` without mocking `FileOps`. - -## Delegating Calls to a Real Object ## - -When using testing doubles (mocks, fakes, stubs, and etc), sometimes -their behaviors will differ from those of the real objects. This -difference could be either intentional (as in simulating an error such -that you can test the error handling code) or unintentional. If your -mocks have different behaviors than the real objects by mistake, you -could end up with code that passes the tests but fails in production. - -You can use the _delegating-to-real_ technique to ensure that your -mock has the same behavior as the real object while retaining the -ability to validate calls. This technique is very similar to the -delegating-to-fake technique, the difference being that we use a real -object instead of a fake. Here's an example: - -``` -using ::testing::_; -using ::testing::AtLeast; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MockFoo() { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DoThis()) - .WillByDefault(Invoke(&real_, &Foo::DoThis)); - ON_CALL(*this, DoThat(_)) - .WillByDefault(Invoke(&real_, &Foo::DoThat)); - ... - } - MOCK_METHOD0(DoThis, ...); - MOCK_METHOD1(DoThat, ...); - ... - private: - Foo real_; -}; -... - - MockFoo mock; - - EXPECT_CALL(mock, DoThis()) - .Times(3); - EXPECT_CALL(mock, DoThat("Hi")) - .Times(AtLeast(1)); - ... use mock in test ... -``` - -With this, Google Mock will verify that your code made the right calls -(with the right arguments, in the right order, called the right number -of times, etc), and a real object will answer the calls (so the -behavior will be the same as in production). This gives you the best -of both worlds. - -## Delegating Calls to a Parent Class ## - -Ideally, you should code to interfaces, whose methods are all pure -virtual. In reality, sometimes you do need to mock a virtual method -that is not pure (i.e, it already has an implementation). For example: - -``` -class Foo { - public: - virtual ~Foo(); - - virtual void Pure(int n) = 0; - virtual int Concrete(const char* str) { ... } -}; - -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); -}; -``` - -Sometimes you may want to call `Foo::Concrete()` instead of -`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub -action, or perhaps your test doesn't need to mock `Concrete()` at all -(but it would be oh-so painful to have to define a new mock class -whenever you don't need to mock one of its methods). - -The trick is to leave a back door in your mock class for accessing the -real methods in the base class: - -``` -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD1(Pure, void(int n)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD1(Concrete, int(const char* str)); - - // Use this to call Concrete() defined in Foo. - int FooConcrete(const char* str) { return Foo::Concrete(str); } -}; -``` - -Now, you can call `Foo::Concrete()` inside an action by: - -``` -using ::testing::_; -using ::testing::Invoke; -... - EXPECT_CALL(foo, Concrete(_)) - .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -or tell the mock object that you don't want to mock `Concrete()`: - -``` -using ::testing::Invoke; -... - ON_CALL(foo, Concrete(_)) - .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); -``` - -(Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do -that, `MockFoo::Concrete()` will be called (and cause an infinite -recursion) since `Foo::Concrete()` is virtual. That's just how C++ -works.) - -# Using Matchers # - -## Matching Argument Values Exactly ## - -You can specify exactly which arguments a mock method is expecting: - -``` -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(5)) - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", bar)); -``` - -## Using Simple Matchers ## - -You can use matchers to match arguments that have a certain property: - -``` -using ::testing::Ge; -using ::testing::NotNull; -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", NotNull())); - // The second argument must not be NULL. -``` - -A frequently used matcher is `_`, which matches anything: - -``` -using ::testing::_; -using ::testing::NotNull; -... - EXPECT_CALL(foo, DoThat(_, NotNull())); -``` - -## Combining Matchers ## - -You can build complex matchers from existing ones using `AllOf()`, -`AnyOf()`, and `Not()`: - -``` -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -... - // The argument must be > 5 and != 10. - EXPECT_CALL(foo, DoThis(AllOf(Gt(5), - Ne(10)))); - - // The first argument must not contain sub-string "blah". - EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), - NULL)); -``` - -## Casting Matchers ## - -Google Mock matchers are statically typed, meaning that the compiler -can catch your mistake if you use a matcher of the wrong type (for -example, if you use `Eq(5)` to match a `string` argument). Good for -you! - -Sometimes, however, you know what you're doing and want the compiler -to give you some slack. One example is that you have a matcher for -`long` and the argument you want to match is `int`. While the two -types aren't exactly the same, there is nothing really wrong with -using a `Matcher` to match an `int` - after all, we can first -convert the `int` argument to a `long` before giving it to the -matcher. - -To support this need, Google Mock gives you the -`SafeMatcherCast(m)` function. It casts a matcher `m` to type -`Matcher`. To ensure safety, Google Mock checks that (let `U` be the -type `m` accepts): - - 1. Type `T` can be implicitly cast to type `U`; - 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and - 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). - -The code won't compile if any of these conditions isn't met. - -Here's one example: - -``` -using ::testing::SafeMatcherCast; - -// A base class and a child class. -class Base { ... }; -class Derived : public Base { ... }; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(DoThis, void(Derived* derived)); -}; -... - - MockFoo foo; - // m is a Matcher we got from somewhere. - EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); -``` - -If you find `SafeMatcherCast(m)` too limiting, you can use a similar -function `MatcherCast(m)`. The difference is that `MatcherCast` works -as long as you can `static_cast` type `T` to type `U`. - -`MatcherCast` essentially lets you bypass C++'s type system -(`static_cast` isn't always safe as it could throw away information, -for example), so be careful not to misuse/abuse it. - -## Selecting Between Overloaded Functions ## - -If you expect an overloaded function to be called, the compiler may -need some help on which overloaded version it is. - -To disambiguate functions overloaded on the const-ness of this object, -use the `Const()` argument wrapper. - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - ... - MOCK_METHOD0(GetBar, Bar&()); - MOCK_CONST_METHOD0(GetBar, const Bar&()); -}; -... - - MockFoo foo; - Bar bar1, bar2; - EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). - .WillOnce(ReturnRef(bar1)); - EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). - .WillOnce(ReturnRef(bar2)); -``` - -(`Const()` is defined by Google Mock and returns a `const` reference -to its argument.) - -To disambiguate overloaded functions with the same number of arguments -but different argument types, you may need to specify the exact type -of a matcher, either by wrapping your matcher in `Matcher()`, or -using a matcher whose type is fixed (`TypedEq`, `An()`, -etc): - -``` -using ::testing::An; -using ::testing::Lt; -using ::testing::Matcher; -using ::testing::TypedEq; - -class MockPrinter : public Printer { - public: - MOCK_METHOD1(Print, void(int n)); - MOCK_METHOD1(Print, void(char c)); -}; - -TEST(PrinterTest, Print) { - MockPrinter printer; - - EXPECT_CALL(printer, Print(An())); // void Print(int); - EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); - EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); - - printer.Print(3); - printer.Print(6); - printer.Print('a'); -} -``` - -## Performing Different Actions Based on the Arguments ## - -When a mock method is called, the _last_ matching expectation that's -still active will be selected (think "newer overrides older"). So, you -can make a method do different things depending on its argument values -like this: - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Return; -... - // The default case. - EXPECT_CALL(foo, DoThis(_)) - .WillRepeatedly(Return('b')); - - // The more specific case. - EXPECT_CALL(foo, DoThis(Lt(5))) - .WillRepeatedly(Return('a')); -``` - -Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will -be returned; otherwise `'b'` will be returned. - -## Matching Multiple Arguments as a Whole ## - -Sometimes it's not enough to match the arguments individually. For -example, we may want to say that the first argument must be less than -the second argument. The `With()` clause allows us to match -all arguments of a mock function as a whole. For example, - -``` -using ::testing::_; -using ::testing::Lt; -using ::testing::Ne; -... - EXPECT_CALL(foo, InRange(Ne(0), _)) - .With(Lt()); -``` - -says that the first argument of `InRange()` must not be 0, and must be -less than the second argument. - -The expression inside `With()` must be a matcher of type -`Matcher >`, where `A1`, ..., `An` are the -types of the function arguments. - -You can also write `AllArgs(m)` instead of `m` inside `.With()`. The -two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable -than `.With(Lt())`. - -You can use `Args(m)` to match the `n` selected arguments -(as a tuple) against `m`. For example, - -``` -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::Lt; -... - EXPECT_CALL(foo, Blah(_, _, _)) - .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); -``` - -says that `Blah()` will be called with arguments `x`, `y`, and `z` where -`x < y < z`. - -As a convenience and example, Google Mock provides some matchers for -2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_7_CheatSheet.md) for -the complete list. - -Note that if you want to pass the arguments to a predicate of your own -(e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be -written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` -selected arguments as _one_ single tuple to the predicate. - -## Using Matchers as Predicates ## - -Have you noticed that a matcher is just a fancy predicate that also -knows how to describe itself? Many existing algorithms take predicates -as arguments (e.g. those defined in STL's `` header), and -it would be a shame if Google Mock matchers are not allowed to -participate. - -Luckily, you can use a matcher where a unary predicate functor is -expected by wrapping it inside the `Matches()` function. For example, - -``` -#include -#include - -std::vector v; -... -// How many elements in v are >= 10? -const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); -``` - -Since you can build complex matchers from simpler ones easily using -Google Mock, this gives you a way to conveniently construct composite -predicates (doing the same using STL's `` header is just -painful). For example, here's a predicate that's satisfied by any -number that is >= 0, <= 100, and != 50: - -``` -Matches(AllOf(Ge(0), Le(100), Ne(50))) -``` - -## Using Matchers in Google Test Assertions ## - -Since matchers are basically predicates that also know how to describe -themselves, there is a way to take advantage of them in -[Google Test](http://code.google.com/p/googletest/) assertions. It's -called `ASSERT_THAT` and `EXPECT_THAT`: - -``` - ASSERT_THAT(value, matcher); // Asserts that value matches matcher. - EXPECT_THAT(value, matcher); // The non-fatal version. -``` - -For example, in a Google Test test you can write: - -``` -#include "gmock/gmock.h" - -using ::testing::AllOf; -using ::testing::Ge; -using ::testing::Le; -using ::testing::MatchesRegex; -using ::testing::StartsWith; -... - - EXPECT_THAT(Foo(), StartsWith("Hello")); - EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); - ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); -``` - -which (as you can probably guess) executes `Foo()`, `Bar()`, and -`Baz()`, and verifies that: - - * `Foo()` returns a string that starts with `"Hello"`. - * `Bar()` returns a string that matches regular expression `"Line \\d+"`. - * `Baz()` returns a number in the range [5, 10]. - -The nice thing about these macros is that _they read like -English_. They generate informative messages too. For example, if the -first `EXPECT_THAT()` above fails, the message will be something like: - -``` -Value of: Foo() - Actual: "Hi, world!" -Expected: starts with "Hello" -``` - -**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the -[Hamcrest](http://code.google.com/p/hamcrest/) project, which adds -`assertThat()` to JUnit. - -## Using Predicates as Matchers ## - -Google Mock provides a built-in set of matchers. In case you find them -lacking, you can use an arbitray unary predicate function or functor -as a matcher - as long as the predicate accepts a value of the type -you want. You do this by wrapping the predicate inside the `Truly()` -function, for example: - -``` -using ::testing::Truly; - -int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } -... - - // Bar() must be called with an even number. - EXPECT_CALL(foo, Bar(Truly(IsEven))); -``` - -Note that the predicate function / functor doesn't have to return -`bool`. It works as long as the return value can be used as the -condition in statement `if (condition) ...`. - -## Matching Arguments that Are Not Copyable ## - -When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves -away a copy of `bar`. When `Foo()` is called later, Google Mock -compares the argument to `Foo()` with the saved copy of `bar`. This -way, you don't need to worry about `bar` being modified or destroyed -after the `EXPECT_CALL()` is executed. The same is true when you use -matchers like `Eq(bar)`, `Le(bar)`, and so on. - -But what if `bar` cannot be copied (i.e. has no copy constructor)? You -could define your own matcher function and use it with `Truly()`, as -the previous couple of recipes have shown. Or, you may be able to get -away from it if you can guarantee that `bar` won't be changed after -the `EXPECT_CALL()` is executed. Just tell Google Mock that it should -save a reference to `bar`, instead of a copy of it. Here's how: - -``` -using ::testing::Eq; -using ::testing::ByRef; -using ::testing::Lt; -... - // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); - - // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); -``` - -Remember: if you do this, don't change `bar` after the -`EXPECT_CALL()`, or the result is undefined. - -## Validating a Member of an Object ## - -Often a mock function takes a reference to object as an argument. When -matching the argument, you may not want to compare the entire object -against a fixed object, as that may be over-specification. Instead, -you may need to validate a certain member variable or the result of a -certain getter method of the object. You can do this with `Field()` -and `Property()`. More specifically, - -``` -Field(&Foo::bar, m) -``` - -is a matcher that matches a `Foo` object whose `bar` member variable -satisfies matcher `m`. - -``` -Property(&Foo::baz, m) -``` - -is a matcher that matches a `Foo` object whose `baz()` method returns -a value that satisfies matcher `m`. - -For example: - -> | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | -|:-----------------------------|:-----------------------------------| -> | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | - -Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no -argument and be declared as `const`. - -BTW, `Field()` and `Property()` can also match plain pointers to -objects. For instance, - -``` -Field(&Foo::number, Ge(3)) -``` - -matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, -the match will always fail regardless of the inner matcher. - -What if you want to validate more than one members at the same time? -Remember that there is `AllOf()`. - -## Validating the Value Pointed to by a Pointer Argument ## - -C++ functions often take pointers as arguments. You can use matchers -like `IsNull()`, `NotNull()`, and other comparison matchers to match a -pointer, but what if you want to make sure the value _pointed to_ by -the pointer, instead of the pointer itself, has a certain property? -Well, you can use the `Pointee(m)` matcher. - -`Pointee(m)` matches a pointer iff `m` matches the value the pointer -points to. For example: - -``` -using ::testing::Ge; -using ::testing::Pointee; -... - EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); -``` - -expects `foo.Bar()` to be called with a pointer that points to a value -greater than or equal to 3. - -One nice thing about `Pointee()` is that it treats a `NULL` pointer as -a match failure, so you can write `Pointee(m)` instead of - -``` - AllOf(NotNull(), Pointee(m)) -``` - -without worrying that a `NULL` pointer will crash your test. - -Also, did we tell you that `Pointee()` works with both raw pointers -**and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and -etc)? - -What if you have a pointer to pointer? You guessed it - you can use -nested `Pointee()` to probe deeper inside the value. For example, -`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer -that points to a number less than 3 (what a mouthful...). - -## Testing a Certain Property of an Object ## - -Sometimes you want to specify that an object argument has a certain -property, but there is no existing matcher that does this. If you want -good error messages, you should define a matcher. If you want to do it -quick and dirty, you could get away with writing an ordinary function. - -Let's say you have a mock function that takes an object of type `Foo`, -which has an `int bar()` method and an `int baz()` method, and you -want to constrain that the argument's `bar()` value plus its `baz()` -value is a given number. Here's how you can define a matcher to do it: - -``` -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class BarPlusBazEqMatcher : public MatcherInterface { - public: - explicit BarPlusBazEqMatcher(int expected_sum) - : expected_sum_(expected_sum) {} - - virtual bool MatchAndExplain(const Foo& foo, - MatchResultListener* listener) const { - return (foo.bar() + foo.baz()) == expected_sum_; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "bar() + baz() equals " << expected_sum_; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "bar() + baz() does not equal " << expected_sum_; - } - private: - const int expected_sum_; -}; - -inline Matcher BarPlusBazEq(int expected_sum) { - return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); -} - -... - - EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; -``` - -## Matching Containers ## - -Sometimes an STL container (e.g. list, vector, map, ...) is passed to -a mock function and you may want to validate it. Since most STL -containers support the `==` operator, you can write -`Eq(expected_container)` or simply `expected_container` to match a -container exactly. - -Sometimes, though, you may want to be more flexible (for example, the -first element must be an exact match, but the second element can be -any positive number, and so on). Also, containers used in tests often -have a small number of elements, and having to define the expected -container out-of-line is a bit of a hassle. - -You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in -such cases: - -``` -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::Gt; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); -``` - -The above matcher says that the container must have 4 elements, which -must be 1, greater than 0, anything, and 5 respectively. - -If you instead write: - -``` -using ::testing::_; -using ::testing::Gt; -using ::testing::UnorderedElementsAre; -... - - MOCK_METHOD1(Foo, void(const vector& numbers)); -... - - EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); -``` - -It means that the container must have 4 elements, which under some -permutation must be 1, greater than 0, anything, and 5 respectively. - -`ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 -to 10 arguments. If more are needed, you can place them in a C-style -array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` -instead: - -``` -using ::testing::ElementsAreArray; -... - - // ElementsAreArray accepts an array of element values. - const int expected_vector1[] = { 1, 5, 2, 4, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); - - // Or, an array of element matchers. - Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); -``` - -In case the array needs to be dynamically created (and therefore the -array size cannot be inferred by the compiler), you can give -`ElementsAreArray()` an additional argument to specify the array size: - -``` -using ::testing::ElementsAreArray; -... - int* const expected_vector3 = new int[count]; - ... fill expected_vector3 with values ... - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); -``` - -**Tips:** - - * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. - * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. - * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. - * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). - -## Sharing Matchers ## - -Under the hood, a Google Mock matcher object consists of a pointer to -a ref-counted implementation object. Copying matchers is allowed and -very efficient, as only the pointer is copied. When the last matcher -that references the implementation object dies, the implementation -object will be deleted. - -Therefore, if you have some complex matcher that you want to use again -and again, there is no need to build it everytime. Just assign it to a -matcher variable and use that variable repeatedly! For example, - -``` - Matcher in_range = AllOf(Gt(5), Le(10)); - ... use in_range as a matcher in multiple EXPECT_CALLs ... -``` - -# Setting Expectations # - -## Knowing When to Expect ## - -`ON_CALL` is likely the single most under-utilized construct in Google Mock. - -There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). - -Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. - -This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? - -The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. - -Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. - -So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). - -## Ignoring Uninteresting Calls ## - -If you are not interested in how a mock method is called, just don't -say anything about it. In this case, if the method is ever called, -Google Mock will perform its default action to allow the test program -to continue. If you are not happy with the default action taken by -Google Mock, you can override it using `DefaultValue::Set()` -(described later in this document) or `ON_CALL()`. - -Please note that once you expressed interest in a particular mock -method (via `EXPECT_CALL()`), all invocations to it must match some -expectation. If this function is called but the arguments don't match -any `EXPECT_CALL()` statement, it will be an error. - -## Disallowing Unexpected Calls ## - -If a mock method shouldn't be called at all, explicitly say so: - -``` -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -If some calls to the method are allowed, but the rest are not, just -list all the expected calls: - -``` -using ::testing::AnyNumber; -using ::testing::Gt; -... - EXPECT_CALL(foo, Bar(5)); - EXPECT_CALL(foo, Bar(Gt(10))) - .Times(AnyNumber()); -``` - -A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` -statements will be an error. - -## Expecting Ordered Calls ## - -Although an `EXPECT_CALL()` statement defined earlier takes precedence -when Google Mock tries to match a function call with an expectation, -by default calls don't have to happen in the order `EXPECT_CALL()` -statements are written. For example, if the arguments match the -matchers in the third `EXPECT_CALL()`, but not those in the first two, -then the third expectation will be used. - -If you would rather have all calls occur in the order of the -expectations, put the `EXPECT_CALL()` statements in a block where you -define a variable of type `InSequence`: - -``` - using ::testing::_; - using ::testing::InSequence; - - { - InSequence s; - - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(bar, DoThat(_)) - .Times(2); - EXPECT_CALL(foo, DoThis(6)); - } -``` - -In this example, we expect a call to `foo.DoThis(5)`, followed by two -calls to `bar.DoThat()` where the argument can be anything, which are -in turn followed by a call to `foo.DoThis(6)`. If a call occurred -out-of-order, Google Mock will report an error. - -## Expecting Partially Ordered Calls ## - -Sometimes requiring everything to occur in a predetermined order can -lead to brittle tests. For example, we may care about `A` occurring -before both `B` and `C`, but aren't interested in the relative order -of `B` and `C`. In this case, the test should reflect our real intent, -instead of being overly constraining. - -Google Mock allows you to impose an arbitrary DAG (directed acyclic -graph) on the calls. One way to express the DAG is to use the -[After](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. - -Another way is via the `InSequence()` clause (not the same as the -`InSequence` class), which we borrowed from jMock 2. It's less -flexible than `After()`, but more convenient when you have long chains -of sequential calls, as it doesn't require you to come up with -different names for the expectations in the chains. Here's how it -works: - -If we view `EXPECT_CALL()` statements as nodes in a graph, and add an -edge from node A to node B wherever A must occur before B, we can get -a DAG. We use the term "sequence" to mean a directed path in this -DAG. Now, if we decompose the DAG into sequences, we just need to know -which sequences each `EXPECT_CALL()` belongs to in order to be able to -reconstruct the orginal DAG. - -So, to specify the partial order on the expectations we need to do two -things: first to define some `Sequence` objects, and then for each -`EXPECT_CALL()` say which `Sequence` objects it is part -of. Expectations in the same sequence must occur in the order they are -written. For example, - -``` - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(foo, A()) - .InSequence(s1, s2); - EXPECT_CALL(bar, B()) - .InSequence(s1); - EXPECT_CALL(bar, C()) - .InSequence(s2); - EXPECT_CALL(foo, D()) - .InSequence(s2); -``` - -specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> -C -> D`): - -``` - +---> B - | - A ---| - | - +---> C ---> D -``` - -This means that A must occur before B and C, and C must occur before -D. There's no restriction about the order other than these. - -## Controlling When an Expectation Retires ## - -When a mock method is called, Google Mock only consider expectations -that are still active. An expectation is active when created, and -becomes inactive (aka _retires_) when a call that has to occur later -has occurred. For example, in - -``` - using ::testing::_; - using ::testing::Sequence; - - Sequence s1, s2; - - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 - .Times(AnyNumber()) - .InSequence(s1, s2); - EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 - .InSequence(s1); - EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 - .InSequence(s2); -``` - -as soon as either #2 or #3 is matched, #1 will retire. If a warning -`"File too large."` is logged after this, it will be an error. - -Note that an expectation doesn't retire automatically when it's -saturated. For example, - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 -``` - -says that there will be exactly one warning with the message `"File -too large."`. If the second warning contains this message too, #2 will -match again and result in an upper-bound-violated error. - -If this is not what you want, you can ask an expectation to retire as -soon as it becomes saturated: - -``` -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 - .RetiresOnSaturation(); -``` - -Here #2 can be used only once, so if you have two warnings with the -message `"File too large."`, the first will match #2 and the second -will match #1 - there will be no error. - -# Using Actions # - -## Returning References from Mock Methods ## - -If a mock function's return type is a reference, you need to use -`ReturnRef()` instead of `Return()` to return a result: - -``` -using ::testing::ReturnRef; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetBar, Bar&()); -}; -... - - MockFoo foo; - Bar bar; - EXPECT_CALL(foo, GetBar()) - .WillOnce(ReturnRef(bar)); -``` - -## Returning Live Values from Mock Methods ## - -The `Return(x)` action saves a copy of `x` when the action is -_created_, and always returns the same value whenever it's -executed. Sometimes you may want to instead return the _live_ value of -`x` (i.e. its value at the time when the action is _executed_.). - -If the mock function's return type is a reference, you can do it using -`ReturnRef(x)`, as shown in the previous recipe ("Returning References -from Mock Methods"). However, Google Mock doesn't let you use -`ReturnRef()` in a mock function whose return type is not a reference, -as doing that usually indicates a user error. So, what shall you do? - -You may be tempted to try `ByRef()`: - -``` -using testing::ByRef; -using testing::Return; - -class MockFoo : public Foo { - public: - MOCK_METHOD0(GetValue, int()); -}; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(Return(ByRef(x))); - x = 42; - EXPECT_EQ(42, foo.GetValue()); -``` - -Unfortunately, it doesn't work here. The above code will fail with error: - -``` -Value of: foo.GetValue() - Actual: 0 -Expected: 42 -``` - -The reason is that `Return(value)` converts `value` to the actual -return type of the mock function at the time when the action is -_created_, not when it is _executed_. (This behavior was chosen for -the action to be safe when `value` is a proxy object that references -some temporary objects.) As a result, `ByRef(x)` is converted to an -`int` value (instead of a `const int&`) when the expectation is set, -and `Return(ByRef(x))` will always return 0. - -`ReturnPointee(pointer)` was provided to solve this problem -specifically. It returns the value pointed to by `pointer` at the time -the action is _executed_: - -``` -using testing::ReturnPointee; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(ReturnPointee(&x)); // Note the & here. - x = 42; - EXPECT_EQ(42, foo.GetValue()); // This will succeed now. -``` - -## Combining Actions ## - -Want to do more than one thing when a function is called? That's -fine. `DoAll()` allow you to do sequence of actions every time. Only -the return value of the last action in the sequence will be used. - -``` -using ::testing::DoAll; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Bar, bool(int n)); -}; -... - - EXPECT_CALL(foo, Bar(_)) - .WillOnce(DoAll(action_1, - action_2, - ... - action_n)); -``` - -## Mocking Side Effects ## - -Sometimes a method exhibits its effect not via returning a value but -via side effects. For example, it may change some global state or -modify an output argument. To mock side effects, in general you can -define your own action by implementing `::testing::ActionInterface`. - -If all you need to do is to change an output argument, the built-in -`SetArgPointee()` action is convenient: - -``` -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - MOCK_METHOD2(Mutate, void(bool mutate, int* value)); - ... -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, Mutate(true, _)) - .WillOnce(SetArgPointee<1>(5)); -``` - -In this example, when `mutator.Mutate()` is called, we will assign 5 -to the `int` variable pointed to by argument #1 -(0-based). - -`SetArgPointee()` conveniently makes an internal copy of the -value you pass to it, removing the need to keep the value in scope and -alive. The implication however is that the value must have a copy -constructor and assignment operator. - -If the mock method also needs to return a value as well, you can chain -`SetArgPointee()` with `Return()` using `DoAll()`: - -``` -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - ... - MOCK_METHOD1(MutateInt, bool(int* value)); -}; -... - - MockMutator mutator; - EXPECT_CALL(mutator, MutateInt(_)) - .WillOnce(DoAll(SetArgPointee<0>(5), - Return(true))); -``` - -If the output argument is an array, use the -`SetArrayArgument(first, last)` action instead. It copies the -elements in source range `[first, last)` to the array pointed to by -the `N`-th (0-based) argument: - -``` -using ::testing::NotNull; -using ::testing::SetArrayArgument; - -class MockArrayMutator : public ArrayMutator { - public: - MOCK_METHOD2(Mutate, void(int* values, int num_values)); - ... -}; -... - - MockArrayMutator mutator; - int values[5] = { 1, 2, 3, 4, 5 }; - EXPECT_CALL(mutator, Mutate(NotNull(), 5)) - .WillOnce(SetArrayArgument<0>(values, values + 5)); -``` - -This also works when the argument is an output iterator: - -``` -using ::testing::_; -using ::testing::SeArrayArgument; - -class MockRolodex : public Rolodex { - public: - MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); - ... -}; -... - - MockRolodex rolodex; - vector names; - names.push_back("George"); - names.push_back("John"); - names.push_back("Thomas"); - EXPECT_CALL(rolodex, GetNames(_)) - .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); -``` - -## Changing a Mock Object's Behavior Based on the State ## - -If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: - -``` -using ::testing::InSequence; -using ::testing::Return; - -... - { - InSequence seq; - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(my_mock, Flush()); - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(false)); - } - my_mock.FlushIfDirty(); -``` - -This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. - -If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: - -``` -using ::testing::_; -using ::testing::SaveArg; -using ::testing::Return; - -ACTION_P(ReturnPointee, p) { return *p; } -... - int previous_value = 0; - EXPECT_CALL(my_mock, GetPrevValue()) - .WillRepeatedly(ReturnPointee(&previous_value)); - EXPECT_CALL(my_mock, UpdateValue(_)) - .WillRepeatedly(SaveArg<0>(&previous_value)); - my_mock.DoSomethingToUpdateValue(); -``` - -Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. - -## Setting the Default Value for a Return Type ## - -If a mock method's return type is a built-in C++ type or pointer, by -default it will return 0 when invoked. You only need to specify an -action if this default value doesn't work for you. - -Sometimes, you may want to change this default value, or you may want -to specify a default value for types Google Mock doesn't know -about. You can do this using the `::testing::DefaultValue` class -template: - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD0(CalculateBar, Bar()); -}; -... - - Bar default_bar; - // Sets the default return value for type Bar. - DefaultValue::Set(default_bar); - - MockFoo foo; - - // We don't need to specify an action here, as the default - // return value works for us. - EXPECT_CALL(foo, CalculateBar()); - - foo.CalculateBar(); // This should return default_bar. - - // Unsets the default return value. - DefaultValue::Clear(); -``` - -Please note that changing the default value for a type can make you -tests hard to understand. We recommend you to use this feature -judiciously. For example, you may want to make sure the `Set()` and -`Clear()` calls are right next to the code that uses your mock. - -## Setting the Default Actions for a Mock Method ## - -You've learned how to change the default value of a given -type. However, this may be too coarse for your purpose: perhaps you -have two mock methods with the same return type and you want them to -have different behaviors. The `ON_CALL()` macro allows you to -customize your mock's behavior at the method level: - -``` -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Gt; -using ::testing::Return; -... - ON_CALL(foo, Sign(_)) - .WillByDefault(Return(-1)); - ON_CALL(foo, Sign(0)) - .WillByDefault(Return(0)); - ON_CALL(foo, Sign(Gt(0))) - .WillByDefault(Return(1)); - - EXPECT_CALL(foo, Sign(_)) - .Times(AnyNumber()); - - foo.Sign(5); // This should return 1. - foo.Sign(-9); // This should return -1. - foo.Sign(0); // This should return 0. -``` - -As you may have guessed, when there are more than one `ON_CALL()` -statements, the news order take precedence over the older ones. In -other words, the **last** one that matches the function arguments will -be used. This matching order allows you to set up the common behavior -in a mock object's constructor or the test fixture's set-up phase and -specialize the mock's behavior later. - -## Using Functions/Methods/Functors as Actions ## - -If the built-in actions don't suit you, you can easily use an existing -function, method, or functor as an action: - -``` -using ::testing::_; -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(Sum, int(int x, int y)); - MOCK_METHOD1(ComplexJob, bool(int x)); -}; - -int CalculateSum(int x, int y) { return x + y; } - -class Helper { - public: - bool ComplexJob(int x); -}; -... - - MockFoo foo; - Helper helper; - EXPECT_CALL(foo, Sum(_, _)) - .WillOnce(Invoke(CalculateSum)); - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(Invoke(&helper, &Helper::ComplexJob)); - - foo.Sum(5, 6); // Invokes CalculateSum(5, 6). - foo.ComplexJob(10); // Invokes helper.ComplexJob(10); -``` - -The only requirement is that the type of the function, etc must be -_compatible_ with the signature of the mock function, meaning that the -latter's arguments can be implicitly converted to the corresponding -arguments of the former, and the former's return type can be -implicitly converted to that of the latter. So, you can invoke -something whose type is _not_ exactly the same as the mock function, -as long as it's safe to do so - nice, huh? - -## Invoking a Function/Method/Functor Without Arguments ## - -`Invoke()` is very useful for doing actions that are more complex. It -passes the mock function's arguments to the function or functor being -invoked such that the callee has the full context of the call to work -with. If the invoked function is not interested in some or all of the -arguments, it can simply ignore them. - -Yet, a common pattern is that a test author wants to invoke a function -without the arguments of the mock function. `Invoke()` allows her to -do that using a wrapper function that throws away the arguments before -invoking an underlining nullary function. Needless to say, this can be -tedious and obscures the intent of the test. - -`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except -that it doesn't pass the mock function's arguments to the -callee. Here's an example: - -``` -using ::testing::_; -using ::testing::InvokeWithoutArgs; - -class MockFoo : public Foo { - public: - MOCK_METHOD1(ComplexJob, bool(int n)); -}; - -bool Job1() { ... } -... - - MockFoo foo; - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(InvokeWithoutArgs(Job1)); - - foo.ComplexJob(10); // Invokes Job1(). -``` - -## Invoking an Argument of the Mock Function ## - -Sometimes a mock function will receive a function pointer or a functor -(in other words, a "callable") as an argument, e.g. - -``` -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); -}; -``` - -and you may want to invoke this callable argument: - -``` -using ::testing::_; -... - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(...); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -Arghh, you need to refer to a mock function argument but C++ has no -lambda (yet), so you have to define your own action. :-( Or do you -really? - -Well, Google Mock has an action to solve _exactly_ this problem: - -``` - InvokeArgument(arg_1, arg_2, ..., arg_m) -``` - -will invoke the `N`-th (0-based) argument the mock function receives, -with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is -a function pointer or a functor, Google Mock handles them both. - -With that, you could write: - -``` -using ::testing::_; -using ::testing::InvokeArgument; -... - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(InvokeArgument<1>(5)); - // Will execute (*fp)(5), where fp is the - // second argument DoThis() receives. -``` - -What if the callable takes an argument by reference? No problem - just -wrap it inside `ByRef()`: - -``` -... - MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); -... -using ::testing::_; -using ::testing::ByRef; -using ::testing::InvokeArgument; -... - - MockFoo foo; - Helper helper; - ... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, ByRef(helper))); - // ByRef(helper) guarantees that a reference to helper, not a copy of it, - // will be passed to the callable. -``` - -What if the callable takes an argument by reference and we do **not** -wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a -copy_ of the argument, and pass a _reference to the copy_, instead of -a reference to the original value, to the callable. This is especially -handy when the argument is a temporary value: - -``` -... - MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); -... -using ::testing::_; -using ::testing::InvokeArgument; -... - - MockFoo foo; - ... - EXPECT_CALL(foo, DoThat(_)) - .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); - // Will execute (*f)(5.0, string("Hi")), where f is the function pointer - // DoThat() receives. Note that the values 5.0 and string("Hi") are - // temporary and dead once the EXPECT_CALL() statement finishes. Yet - // it's fine to perform this action later, since a copy of the values - // are kept inside the InvokeArgument action. -``` - -## Ignoring an Action's Result ## - -Sometimes you have an action that returns _something_, but you need an -action that returns `void` (perhaps you want to use it in a mock -function that returns `void`, or perhaps it needs to be used in -`DoAll()` and it's not the last in the list). `IgnoreResult()` lets -you do that. For example: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; - -int Process(const MyData& data); -string DoSomething(); - -class MockFoo : public Foo { - public: - MOCK_METHOD1(Abc, void(const MyData& data)); - MOCK_METHOD0(Xyz, bool()); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, Abc(_)) - // .WillOnce(Invoke(Process)); - // The above line won't compile as Process() returns int but Abc() needs - // to return void. - .WillOnce(IgnoreResult(Invoke(Process))); - - EXPECT_CALL(foo, Xyz()) - .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), - // Ignores the string DoSomething() returns. - Return(true))); -``` - -Note that you **cannot** use `IgnoreResult()` on an action that already -returns `void`. Doing so will lead to ugly compiler errors. - -## Selecting an Action's Arguments ## - -Say you have a mock function `Foo()` that takes seven arguments, and -you have a custom action that you want to invoke when `Foo()` is -called. Trouble is, the custom action only wants three arguments: - -``` -using ::testing::_; -using ::testing::Invoke; -... - MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight)); -... - -bool IsVisibleInQuadrant1(bool visible, int x, int y) { - return visible && x >= 0 && y >= 0; -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( -``` - -To please the compiler God, you can to define an "adaptor" that has -the same signature as `Foo()` and calls the custom action with the -right arguments: - -``` -using ::testing::_; -using ::testing::Invoke; - -bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight) { - return IsVisibleInQuadrant1(visible, x, y); -} -... - - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. -``` - -But isn't this awkward? - -Google Mock provides a generic _action adaptor_, so you can spend your -time minding more important business than writing your own -adaptors. Here's the syntax: - -``` - WithArgs(action) -``` - -creates an action that passes the arguments of the mock function at -the given indices (0-based) to the inner `action` and performs -it. Using `WithArgs`, our original example can be written as: - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::WithArgs; -... - EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) - .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); - // No need to define your own adaptor. -``` - -For better readability, Google Mock also gives you: - - * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and - * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. - -As you may have realized, `InvokeWithoutArgs(...)` is just syntactic -sugar for `WithoutArgs(Inovke(...))`. - -Here are more tips: - - * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. - * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. - * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. - * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. - -## Ignoring Arguments in Action Functions ## - -The selecting-an-action's-arguments recipe showed us one way to make a -mock function and an action with incompatible argument lists fit -together. The downside is that wrapping the action in -`WithArgs<...>()` can get tedious for people writing the tests. - -If you are defining a function, method, or functor to be used with -`Invoke*()`, and you are not interested in some of its arguments, an -alternative to `WithArgs` is to declare the uninteresting arguments as -`Unused`. This makes the definition less cluttered and less fragile in -case the types of the uninteresting arguments change. It could also -increase the chance the action function can be reused. For example, -given - -``` - MOCK_METHOD3(Foo, double(const string& label, double x, double y)); - MOCK_METHOD3(Bar, double(int index, double x, double y)); -``` - -instead of - -``` -using ::testing::_; -using ::testing::Invoke; - -double DistanceToOriginWithLabel(const string& label, double x, double y) { - return sqrt(x*x + y*y); -} - -double DistanceToOriginWithIndex(int index, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOriginWithLabel)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOriginWithIndex)); -``` - -you could write - -``` -using ::testing::_; -using ::testing::Invoke; -using ::testing::Unused; - -double DistanceToOrigin(Unused, double x, double y) { - return sqrt(x*x + y*y); -} -... - - EXEPCT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOrigin)); - EXEPCT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOrigin)); -``` - -## Sharing Actions ## - -Just like matchers, a Google Mock action object consists of a pointer -to a ref-counted implementation object. Therefore copying actions is -also allowed and very efficient. When the last action that references -the implementation object dies, the implementation object will be -deleted. - -If you have some complex action that you want to use again and again, -you may not have to build it from scratch everytime. If the action -doesn't have an internal state (i.e. if it always does the same thing -no matter how many times it has been called), you can assign it to an -action variable and use that variable repeatedly. For example: - -``` - Action set_flag = DoAll(SetArgPointee<0>(5), - Return(true)); - ... use set_flag in .WillOnce() and .WillRepeatedly() ... -``` - -However, if the action has its own state, you may be surprised if you -share the action object. Suppose you have an action factory -`IncrementCounter(init)` which creates an action that increments and -returns a counter whose initial value is `init`, using two actions -created from the same expression and using a shared action will -exihibit different behaviors. Example: - -``` - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(IncrementCounter(0)); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(IncrementCounter(0)); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 1 - Blah() uses a different - // counter than Bar()'s. -``` - -versus - -``` - Action increment = IncrementCounter(0); - - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(increment); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(increment); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 3 - the counter is shared. -``` - -# Misc Recipes on Using Google Mock # - -## Making the Compilation Faster ## - -Believe it or not, the _vast majority_ of the time spent on compiling -a mock class is in generating its constructor and destructor, as they -perform non-trivial tasks (e.g. verification of the -expectations). What's more, mock methods with different signatures -have different types and thus their constructors/destructors need to -be generated by the compiler separately. As a result, if you mock many -different types of methods, compiling your mock class can get really -slow. - -If you are experiencing slow compilation, you can move the definition -of your mock class' constructor and destructor out of the class body -and into a `.cpp` file. This way, even if you `#include` your mock -class in N files, the compiler only needs to generate its constructor -and destructor once, resulting in a much faster compilation. - -Let's illustrate the idea using an example. Here's the definition of a -mock class before applying this recipe: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // Since we don't declare the constructor or the destructor, - // the compiler will generate them in every translation unit - // where this mock class is used. - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` - -After the change, it would look like: - -``` -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // The constructor and destructor are declared, but not defined, here. - MockFoo(); - virtual ~MockFoo(); - - MOCK_METHOD0(DoThis, int()); - MOCK_METHOD1(DoThat, bool(const char* str)); - ... more mock methods ... -}; -``` -and -``` -// File mock_foo.cpp. -#include "path/to/mock_foo.h" - -// The definitions may appear trivial, but the functions actually do a -// lot of things through the constructors/destructors of the member -// variables used to implement the mock methods. -MockFoo::MockFoo() {} -MockFoo::~MockFoo() {} -``` - -## Forcing a Verification ## - -When it's being destoyed, your friendly mock object will automatically -verify that all expectations on it have been satisfied, and will -generate [Google Test](http://code.google.com/p/googletest/) failures -if not. This is convenient as it leaves you with one less thing to -worry about. That is, unless you are not sure if your mock object will -be destoyed. - -How could it be that your mock object won't eventually be destroyed? -Well, it might be created on the heap and owned by the code you are -testing. Suppose there's a bug in that code and it doesn't delete the -mock object properly - you could end up with a passing test when -there's actually a bug. - -Using a heap checker is a good idea and can alleviate the concern, but -its implementation may not be 100% reliable. So, sometimes you do want -to _force_ Google Mock to verify a mock object before it is -(hopefully) destructed. You can do this with -`Mock::VerifyAndClearExpectations(&mock_object)`: - -``` -TEST(MyServerTest, ProcessesRequest) { - using ::testing::Mock; - - MockFoo* const foo = new MockFoo; - EXPECT_CALL(*foo, ...)...; - // ... other expectations ... - - // server now owns foo. - MyServer server(foo); - server.ProcessRequest(...); - - // In case that server's destructor will forget to delete foo, - // this will verify the expectations anyway. - Mock::VerifyAndClearExpectations(foo); -} // server is destroyed when it goes out of scope here. -``` - -**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a -`bool` to indicate whether the verification was successful (`true` for -yes), so you can wrap that function call inside a `ASSERT_TRUE()` if -there is no point going further when the verification has failed. - -## Using Check Points ## - -Sometimes you may want to "reset" a mock object at various check -points in your test: at each check point, you verify that all existing -expectations on the mock object have been satisfied, and then you set -some new expectations on it as if it's newly created. This allows you -to work with a mock object in "phases" whose sizes are each -manageable. - -One such scenario is that in your test's `SetUp()` function, you may -want to put the object you are testing into a certain state, with the -help from a mock object. Once in the desired state, you want to clear -all expectations on the mock, such that in the `TEST_F` body you can -set fresh expectations on it. - -As you may have figured out, the `Mock::VerifyAndClearExpectations()` -function we saw in the previous recipe can help you here. Or, if you -are using `ON_CALL()` to set default actions on the mock object and -want to clear the default actions as well, use -`Mock::VerifyAndClear(&mock_object)` instead. This function does what -`Mock::VerifyAndClearExpectations(&mock_object)` does and returns the -same `bool`, **plus** it clears the `ON_CALL()` statements on -`mock_object` too. - -Another trick you can use to achieve the same effect is to put the -expectations in sequences and insert calls to a dummy "check-point" -function at specific places. Then you can verify that the mock -function calls do happen at the right time. For example, if you are -exercising code: - -``` -Foo(1); -Foo(2); -Foo(3); -``` - -and want to verify that `Foo(1)` and `Foo(3)` both invoke -`mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: - -``` -using ::testing::MockFunction; - -TEST(FooTest, InvokesBarCorrectly) { - MyMock mock; - // Class MockFunction has exactly one mock method. It is named - // Call() and has type F. - MockFunction check; - { - InSequence s; - - EXPECT_CALL(mock, Bar("a")); - EXPECT_CALL(check, Call("1")); - EXPECT_CALL(check, Call("2")); - EXPECT_CALL(mock, Bar("a")); - } - Foo(1); - check.Call("1"); - Foo(2); - check.Call("2"); - Foo(3); -} -``` - -The expectation spec says that the first `Bar("a")` must happen before -check point "1", the second `Bar("a")` must happen after check point "2", -and nothing should happen between the two check points. The explicit -check points make it easy to tell which `Bar("a")` is called by which -call to `Foo()`. - -## Mocking Destructors ## - -Sometimes you want to make sure a mock object is destructed at the -right time, e.g. after `bar->A()` is called but before `bar->B()` is -called. We already know that you can specify constraints on the order -of mock function calls, so all we need to do is to mock the destructor -of the mock function. - -This sounds simple, except for one problem: a destructor is a special -function with special syntax and special semantics, and the -`MOCK_METHOD0` macro doesn't work for it: - -``` - MOCK_METHOD0(~MockFoo, void()); // Won't compile! -``` - -The good news is that you can use a simple pattern to achieve the same -effect. First, add a mock function `Die()` to your mock class and call -it in the destructor, like this: - -``` -class MockFoo : public Foo { - ... - // Add the following two lines to the mock class. - MOCK_METHOD0(Die, void()); - virtual ~MockFoo() { Die(); } -}; -``` - -(If the name `Die()` clashes with an existing symbol, choose another -name.) Now, we have translated the problem of testing when a `MockFoo` -object dies to testing when its `Die()` method is called: - -``` - MockFoo* foo = new MockFoo; - MockBar* bar = new MockBar; - ... - { - InSequence s; - - // Expects *foo to die after bar->A() and before bar->B(). - EXPECT_CALL(*bar, A()); - EXPECT_CALL(*foo, Die()); - EXPECT_CALL(*bar, B()); - } -``` - -And that's that. - -## Using Google Mock and Threads ## - -**IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on -platforms where Google Mock is thread-safe. Currently these are only -platforms that support the pthreads library (this includes Linux and Mac). -To make it thread-safe on other platforms we only need to implement -some synchronization operations in `"gtest/internal/gtest-port.h"`. - -In a **unit** test, it's best if you could isolate and test a piece of -code in a single-threaded context. That avoids race conditions and -dead locks, and makes debugging your test much easier. - -Yet many programs are multi-threaded, and sometimes to test something -we need to pound on it from more than one thread. Google Mock works -for this purpose too. - -Remember the steps for using a mock: - - 1. Create a mock object `foo`. - 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. - 1. The code under test calls methods of `foo`. - 1. Optionally, verify and reset the mock. - 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. - -If you follow the following simple rules, your mocks and threads can -live happily togeter: - - * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. - * Obviously, you can do step #1 without locking. - * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? - * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. - -If you violate the rules (for example, if you set expectations on a -mock while another thread is calling its methods), you get undefined -behavior. That's not fun, so don't do it. - -Google Mock guarantees that the action for a mock function is done in -the same thread that called the mock function. For example, in - -``` - EXPECT_CALL(mock, Foo(1)) - .WillOnce(action1); - EXPECT_CALL(mock, Foo(2)) - .WillOnce(action2); -``` - -if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, -Google Mock will execute `action1` in thread 1 and `action2` in thread -2. - -Google Mock does _not_ impose a sequence on actions performed in -different threads (doing so may create deadlocks as the actions may -need to cooperate). This means that the execution of `action1` and -`action2` in the above example _may_ interleave. If this is a problem, -you should add proper synchronization logic to `action1` and `action2` -to make the test thread-safe. - - -Also, remember that `DefaultValue` is a global resource that -potentially affects _all_ living mock objects in your -program. Naturally, you won't want to mess with it from multiple -threads or when there still are mocks in action. - -## Controlling How Much Information Google Mock Prints ## - -When Google Mock sees something that has the potential of being an -error (e.g. a mock function with no expectation is called, a.k.a. an -uninteresting call, which is allowed but perhaps you forgot to -explicitly ban the call), it prints some warning messages, including -the arguments of the function and the return value. Hopefully this -will remind you to take a look and see if there is indeed a problem. - -Sometimes you are confident that your tests are correct and may not -appreciate such friendly messages. Some other times, you are debugging -your tests or learning about the behavior of the code you are testing, -and wish you could observe every mock call that happens (including -argument values and the return value). Clearly, one size doesn't fit -all. - -You can control how much Google Mock tells you using the -`--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string -with three possible values: - - * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. - * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. - * `error`: Google Mock will print errors only (least verbose). - -Alternatively, you can adjust the value of that flag from within your -tests like so: - -``` - ::testing::FLAGS_gmock_verbose = "error"; -``` - -Now, judiciously use the right flag to enable Google Mock serve you better! - -## Gaining Super Vision into Mock Calls ## - -You have a test using Google Mock. It fails: Google Mock tells you -that some expectations aren't satisfied. However, you aren't sure why: -Is there a typo somewhere in the matchers? Did you mess up the order -of the `EXPECT_CALL`s? Or is the code under test doing something -wrong? How can you find out the cause? - -Won't it be nice if you have X-ray vision and can actually see the -trace of all `EXPECT_CALL`s and mock method calls as they are made? -For each call, would you like to see its actual argument values and -which `EXPECT_CALL` Google Mock thinks it matches? - -You can unlock this power by running your test with the -`--gmock_verbose=info` flag. For example, given the test program: - -``` -using testing::_; -using testing::HasSubstr; -using testing::Return; - -class MockFoo { - public: - MOCK_METHOD2(F, void(const string& x, const string& y)); -}; - -TEST(Foo, Bar) { - MockFoo mock; - EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); - EXPECT_CALL(mock, F("a", "b")); - EXPECT_CALL(mock, F("c", HasSubstr("d"))); - - mock.F("a", "good"); - mock.F("a", "b"); -} -``` - -if you run it with `--gmock_verbose=info`, you will see this output: - -``` -[ RUN ] Foo.Bar - -foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked -foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked -foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked -foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... - Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") -foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... - Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") -foo_test.cc:16: Failure -Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... - Expected: to be called once - Actual: never called - unsatisfied and active -[ FAILED ] Foo.Bar -``` - -Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo -and should actually be `"a"`. With the above message, you should see -that the actual `F("a", "good")` call is matched by the first -`EXPECT_CALL`, not the third as you thought. From that it should be -obvious that the third `EXPECT_CALL` is written wrong. Case solved. - -## Running Tests in Emacs ## - -If you build and run your tests in Emacs, the source file locations of -Google Mock and [Google Test](http://code.google.com/p/googletest/) -errors will be highlighted. Just press `` on one of them and -you'll be taken to the offending line. Or, you can just type `C-x `` -to jump to the next error. - -To make it even easier, you can add the following lines to your -`~/.emacs` file: - -``` -(global-set-key "\M-m" 'compile) ; m is for make -(global-set-key [M-down] 'next-error) -(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) -``` - -Then you can type `M-m` to start a build, or `M-up`/`M-down` to move -back and forth between errors. - -## Fusing Google Mock Source Files ## - -Google Mock's implementation consists of dozens of files (excluding -its own tests). Sometimes you may want them to be packaged up in -fewer files instead, such that you can easily copy them to a new -machine and start hacking there. For this we provide an experimental -Python script `fuse_gmock_files.py` in the `scripts/` directory -(starting with release 1.2.0). Assuming you have Python 2.4 or above -installed on your machine, just go to that directory and run -``` -python fuse_gmock_files.py OUTPUT_DIR -``` - -and you should see an `OUTPUT_DIR` directory being created with files -`gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. -These three files contain everything you need to use Google Mock (and -Google Test). Just copy them to anywhere you want and you are ready -to write tests and use mocks. You can use the -[scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests -against them. - -# Extending Google Mock # - -## Writing New Matchers Quickly ## - -The `MATCHER*` family of macros can be used to define custom matchers -easily. The syntax: - -``` -MATCHER(name, description_string_expression) { statements; } -``` - -will define a matcher with the given name that executes the -statements, which must return a `bool` to indicate if the match -succeeds. Inside the statements, you can refer to the value being -matched by `arg`, and refer to its type by `arg_type`. - -The description string is a `string`-typed expression that documents -what the matcher does, and is used to generate the failure message -when the match fails. It can (and should) reference the special -`bool` variable `negation`, and should evaluate to the description of -the matcher when `negation` is `false`, or that of the matcher's -negation when `negation` is `true`. - -For convenience, we allow the description string to be empty (`""`), -in which case Google Mock will use the sequence of words in the -matcher name as the description. - -For example: -``` -MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } -``` -allows you to write -``` - // Expects mock_foo.Bar(n) to be called where n is divisible by 7. - EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); -``` -or, -``` -using ::testing::Not; -... - EXPECT_THAT(some_expression, IsDivisibleBy7()); - EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); -``` -If the above assertions fail, they will print something like: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 -... - Value of: some_other_expression - Expected: not (is divisible by 7) - Actual: 21 -``` -where the descriptions `"is divisible by 7"` and `"not (is divisible -by 7)"` are automatically calculated from the matcher name -`IsDivisibleBy7`. - -As you may have noticed, the auto-generated descriptions (especially -those for the negation) may not be so great. You can always override -them with a string expression of your own: -``` -MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + - " divisible by 7") { - return (arg % 7) == 0; -} -``` - -Optionally, you can stream additional information to a hidden argument -named `result_listener` to explain the match result. For example, a -better definition of `IsDivisibleBy7` is: -``` -MATCHER(IsDivisibleBy7, "") { - if ((arg % 7) == 0) - return true; - - *result_listener << "the remainder is " << (arg % 7); - return false; -} -``` - -With this definition, the above assertion will give a better message: -``` - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 (the remainder is 6) -``` - -You should let `MatchAndExplain()` print _any additional information_ -that can help a user understand the match result. Note that it should -explain why the match succeeds in case of a success (unless it's -obvious) - this is useful when the matcher is used inside -`Not()`. There is no need to print the argument value itself, as -Google Mock already prints it for you. - -**Notes:** - - 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. - 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. - -## Writing New Parameterized Matchers Quickly ## - -Sometimes you'll want to define a matcher that has parameters. For that you -can use the macro: -``` -MATCHER_P(name, param_name, description_string) { statements; } -``` -where the description string can be either `""` or a string expression -that references `negation` and `param_name`. - -For example: -``` -MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -``` -will allow you to write: -``` - EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -``` -which may lead to this message (assuming `n` is 10): -``` - Value of: Blah("a") - Expected: has absolute value 10 - Actual: -9 -``` - -Note that both the matcher description and its parameter are -printed, making the message human-friendly. - -In the matcher definition body, you can write `foo_type` to -reference the type of a parameter named `foo`. For example, in the -body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write -`value_type` to refer to the type of `value`. - -Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to -`MATCHER_P10` to support multi-parameter matchers: -``` -MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } -``` - -Please note that the custom description string is for a particular -**instance** of the matcher, where the parameters have been bound to -actual values. Therefore usually you'll want the parameter values to -be part of the description. Google Mock lets you do that by -referencing the matcher parameters in the description string -expression. - -For example, -``` - using ::testing::PrintToString; - MATCHER_P2(InClosedRange, low, hi, - std::string(negation ? "isn't" : "is") + " in range [" + - PrintToString(low) + ", " + PrintToString(hi) + "]") { - return low <= arg && arg <= hi; - } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the message: -``` - Expected: is in range [4, 6] -``` - -If you specify `""` as the description, the failure message will -contain the sequence of words in the matcher name followed by the -parameter values printed as a tuple. For example, -``` - MATCHER_P2(InClosedRange, low, hi, "") { ... } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` -would generate a failure that contains the text: -``` - Expected: in closed range (4, 6) -``` - -For the purpose of typing, you can view -``` -MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -``` -as shorthand for -``` -template -FooMatcherPk -Foo(p1_type p1, ..., pk_type pk) { ... } -``` - -When you write `Foo(v1, ..., vk)`, the compiler infers the types of -the parameters `v1`, ..., and `vk` for you. If you are not happy with -the result of the type inference, you can specify the types by -explicitly instantiating the template, as in `Foo(5, false)`. -As said earlier, you don't get to (or need to) specify -`arg_type` as that's determined by the context in which the matcher -is used. - -You can assign the result of expression `Foo(p1, ..., pk)` to a -variable of type `FooMatcherPk`. This can be -useful when composing matchers. Matchers that don't have a parameter -or have only one parameter have special types: you can assign `Foo()` -to a `FooMatcher`-typed variable, and assign `Foo(p)` to a -`FooMatcherP`-typed variable. - -While you can instantiate a matcher template with reference types, -passing the parameters by pointer usually makes your code more -readable. If, however, you still want to pass a parameter by -reference, be aware that in the failure message generated by the -matcher you will see the value of the referenced object but not its -address. - -You can overload matchers with different numbers of parameters: -``` -MATCHER_P(Blah, a, description_string_1) { ... } -MATCHER_P2(Blah, a, b, description_string_2) { ... } -``` - -While it's tempting to always use the `MATCHER*` macros when defining -a new matcher, you should also consider implementing -`MatcherInterface` or using `MakePolymorphicMatcher()` instead (see -the recipes that follow), especially if you need to use the matcher a -lot. While these approaches require more work, they give you more -control on the types of the value being matched and the matcher -parameters, which in general leads to better compiler error messages -that pay off in the long run. They also allow overloading matchers -based on parameter types (as opposed to just based on the number of -parameters). - -## Writing New Monomorphic Matchers ## - -A matcher of argument type `T` implements -`::testing::MatcherInterface` and does two things: it tests whether a -value of type `T` matches the matcher, and can describe what kind of -values it matches. The latter ability is used for generating readable -error messages when expectations are violated. - -The interface looks like this: - -``` -class MatchResultListener { - public: - ... - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x); - - // Returns the underlying ostream. - ::std::ostream* stream(); -}; - -template -class MatcherInterface { - public: - virtual ~MatcherInterface(); - - // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Describes this matcher to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. - virtual void DescribeNegationTo(::std::ostream* os) const; -}; -``` - -If you need a custom matcher but `Truly()` is not a good option (for -example, you may not be happy with the way `Truly(predicate)` -describes itself, or you may want your matcher to be polymorphic as -`Eq(value)` is), you can define a matcher to do whatever you want in -two steps: first implement the matcher interface, and then define a -factory function to create a matcher instance. The second step is not -strictly needed but it makes the syntax of using the matcher nicer. - -For example, you can define a matcher to test whether an `int` is -divisible by 7 and then use it like this: -``` -using ::testing::MakeMatcher; -using ::testing::Matcher; -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; - -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { - return (n % 7) == 0; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "is divisible by 7"; - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "is not divisible by 7"; - } -}; - -inline Matcher DivisibleBy7() { - return MakeMatcher(new DivisibleBy7Matcher); -} -... - - EXPECT_CALL(foo, Bar(DivisibleBy7())); -``` - -You may improve the matcher message by streaming additional -information to the `listener` argument in `MatchAndExplain()`: - -``` -class DivisibleBy7Matcher : public MatcherInterface { - public: - virtual bool MatchAndExplain(int n, - MatchResultListener* listener) const { - const int remainder = n % 7; - if (remainder != 0) { - *listener << "the remainder is " << remainder; - } - return remainder == 0; - } - ... -}; -``` - -Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: -``` -Value of: x -Expected: is divisible by 7 - Actual: 23 (the remainder is 2) -``` - -## Writing New Polymorphic Matchers ## - -You've learned how to write your own matchers in the previous -recipe. Just one problem: a matcher created using `MakeMatcher()` only -works for one particular type of arguments. If you want a -_polymorphic_ matcher that works with arguments of several types (for -instance, `Eq(x)` can be used to match a `value` as long as `value` == -`x` compiles -- `value` and `x` don't have to share the same type), -you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit -involved. - -Fortunately, most of the time you can define a polymorphic matcher -easily with the help of `MakePolymorphicMatcher()`. Here's how you can -define `NotNull()` as an example: - -``` -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -using ::testing::NotNull; -using ::testing::PolymorphicMatcher; - -class NotNullMatcher { - public: - // To implement a polymorphic matcher, first define a COPYABLE class - // that has three members MatchAndExplain(), DescribeTo(), and - // DescribeNegationTo(), like the following. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, - MatchResultListener* /* listener */) const { - return p != NULL; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } -}; - -// To construct a polymorphic matcher, pass an instance of the class -// to MakePolymorphicMatcher(). Note the return type. -inline PolymorphicMatcher NotNull() { - return MakePolymorphicMatcher(NotNullMatcher()); -} -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -**Note:** Your polymorphic matcher class does **not** need to inherit from -`MatcherInterface` or any other class, and its methods do **not** need -to be virtual. - -Like in a monomorphic matcher, you may explain the match result by -streaming additional information to the `listener` argument in -`MatchAndExplain()`. - -## Writing New Cardinalities ## - -A cardinality is used in `Times()` to tell Google Mock how many times -you expect a call to occur. It doesn't have to be exact. For example, -you can say `AtLeast(5)` or `Between(2, 4)`. - -If the built-in set of cardinalities doesn't suit you, you are free to -define your own by implementing the following interface (in namespace -`testing`): - -``` -class CardinalityInterface { - public: - virtual ~CardinalityInterface(); - - // Returns true iff call_count calls will satisfy this cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true iff call_count calls will saturate this cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; -}; -``` - -For example, to specify that a call must occur even number of times, -you can write - -``` -using ::testing::Cardinality; -using ::testing::CardinalityInterface; -using ::testing::MakeCardinality; - -class EvenNumberCardinality : public CardinalityInterface { - public: - virtual bool IsSatisfiedByCallCount(int call_count) const { - return (call_count % 2) == 0; - } - - virtual bool IsSaturatedByCallCount(int call_count) const { - return false; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "called even number of times"; - } -}; - -Cardinality EvenNumber() { - return MakeCardinality(new EvenNumberCardinality); -} -... - - EXPECT_CALL(foo, Bar(3)) - .Times(EvenNumber()); -``` - -## Writing New Actions Quickly ## - -If the built-in actions don't work for you, and you find it -inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` -family to quickly define a new action that can be used in your code as -if it's a built-in action. - -By writing -``` -ACTION(name) { statements; } -``` -in a namespace scope (i.e. not inside a class or function), you will -define an action with the given name that executes the statements. -The value returned by `statements` will be used as the return value of -the action. Inside the statements, you can refer to the K-th -(0-based) argument of the mock function as `argK`. For example: -``` -ACTION(IncrementArg1) { return ++(*arg1); } -``` -allows you to write -``` -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function -arguments. Rest assured that your code is type-safe though: -you'll get a compiler error if `*arg1` doesn't support the `++` -operator, or if the type of `++(*arg1)` isn't compatible with the mock -function's return type. - -Another example: -``` -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` -defines an action `Foo()` that invokes argument #2 (a function pointer) -with 5, calls function `Blah()`, sets the value pointed to by argument -#1 to 0, and returns argument #0. - -For more convenience and flexibility, you can also use the following -pre-defined symbols in the body of `ACTION`: - -| `argK_type` | The type of the K-th (0-based) argument of the mock function | -|:------------|:-------------------------------------------------------------| -| `args` | All arguments of the mock function as a tuple | -| `args_type` | The type of all arguments of the mock function as a tuple | -| `return_type` | The return type of the mock function | -| `function_type` | The type of the mock function | - -For example, when using an `ACTION` as a stub action for mock function: -``` -int DoSomething(bool flag, int* ptr); -``` -we have: -| **Pre-defined Symbol** | **Is Bound To** | -|:-----------------------|:----------------| -| `arg0` | the value of `flag` | -| `arg0_type` | the type `bool` | -| `arg1` | the value of `ptr` | -| `arg1_type` | the type `int*` | -| `args` | the tuple `(flag, ptr)` | -| `args_type` | the type `std::tr1::tuple` | -| `return_type` | the type `int` | -| `function_type` | the type `int(bool, int*)` | - -## Writing New Parameterized Actions Quickly ## - -Sometimes you'll want to parameterize an action you define. For that -we have another macro -``` -ACTION_P(name, param) { statements; } -``` - -For example, -``` -ACTION_P(Add, n) { return arg0 + n; } -``` -will allow you to write -``` -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term _arguments_ for the values used to -invoke the mock function, and the term _parameters_ for the values -used to instantiate an action. - -Note that you don't need to provide the type of the parameter either. -Suppose the parameter is named `param`, you can also use the -Google-Mock-defined symbol `param_type` to refer to the type of the -parameter as inferred by the compiler. For example, in the body of -`ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. - -Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support -multi-parameter actions. For example, -``` -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` -lets you write -``` -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the -number of parameters is 0. - -You can also easily define actions overloaded on the number of parameters: -``` -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -## Restricting the Type of an Argument or Parameter in an ACTION ## - -For maximum brevity and reusability, the `ACTION*` macros don't ask -you to provide the types of the mock function arguments and the action -parameters. Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. -There are several tricks to do that. For example: -``` -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` -where `StaticAssertTypeEq` is a compile-time assertion in Google Test -that verifies two types are the same. - -## Writing New Action Templates Quickly ## - -Sometimes you want to give an action explicit template parameters that -cannot be inferred from its value parameters. `ACTION_TEMPLATE()` -supports that and can be viewed as an extension to `ACTION()` and -`ACTION_P*()`. - -The syntax: -``` -ACTION_TEMPLATE(ActionName, - HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), - AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -``` - -defines an action template that takes _m_ explicit template parameters -and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is -between 0 and 10. `name_i` is the name of the i-th template -parameter, and `kind_i` specifies whether it's a `typename`, an -integral constant, or a template. `p_i` is the name of the i-th value -parameter. - -Example: -``` -// DuplicateArg(output) converts the k-th argument of the mock -// function to type T and copies it to *output. -ACTION_TEMPLATE(DuplicateArg, - // Note the comma between int and k: - HAS_2_TEMPLATE_PARAMS(int, k, typename, T), - AND_1_VALUE_PARAMS(output)) { - *output = T(std::tr1::get(args)); -} -``` - -To create an instance of an action template, write: -``` - ActionName(v1, ..., v_n) -``` -where the `t`s are the template arguments and the -`v`s are the value arguments. The value argument -types are inferred by the compiler. For example: -``` -using ::testing::_; -... - int n; - EXPECT_CALL(mock, Foo(_, _)) - .WillOnce(DuplicateArg<1, unsigned char>(&n)); -``` - -If you want to explicitly specify the value argument types, you can -provide additional template arguments: -``` - ActionName(v1, ..., v_n) -``` -where `u_i` is the desired type of `v_i`. - -`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the -number of value parameters, but not on the number of template -parameters. Without the restriction, the meaning of the following is -unclear: - -``` - OverloadedAction(x); -``` - -Are we using a single-template-parameter action where `bool` refers to -the type of `x`, or a two-template-parameter action where the compiler -is asked to infer the type of `x`? - -## Using the ACTION Object's Type ## - -If you are writing a function that returns an `ACTION` object, you'll -need to know its type. The type depends on the macro used to define -the action and the parameter types. The rule is relatively simple: -| **Given Definition** | **Expression** | **Has Type** | -|:---------------------|:---------------|:-------------| -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | -| ... | ... | ... | - -Note that we have to pick different suffixes (`Action`, `ActionP`, -`ActionP2`, and etc) for actions with different numbers of value -parameters, or the action definitions cannot be overloaded on the -number of them. - -## Writing New Monomorphic Actions ## - -While the `ACTION*` macros are very convenient, sometimes they are -inappropriate. For example, despite the tricks shown in the previous -recipes, they don't let you directly specify the types of the mock -function arguments and the action parameters, which in general leads -to unoptimized compiler error messages that can baffle unfamiliar -users. They also don't allow overloading actions based on parameter -types without jumping through some hoops. - -An alternative to the `ACTION*` macros is to implement -`::testing::ActionInterface`, where `F` is the type of the mock -function in which the action will be used. For example: - -``` -template class ActionInterface { - public: - virtual ~ActionInterface(); - - // Performs the action. Result is the return type of function type - // F, and ArgumentTuple is the tuple of arguments of F. - // - // For example, if F is int(bool, const string&), then Result would - // be int, and ArgumentTuple would be tr1::tuple. - virtual Result Perform(const ArgumentTuple& args) = 0; -}; - -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::MakeAction; - -typedef int IncrementMethod(int*); - -class IncrementArgumentAction : public ActionInterface { - public: - virtual int Perform(const tr1::tuple& args) { - int* p = tr1::get<0>(args); // Grabs the first argument. - return *p++; - } -}; - -Action IncrementArgument() { - return MakeAction(new IncrementArgumentAction); -} -... - - EXPECT_CALL(foo, Baz(_)) - .WillOnce(IncrementArgument()); - - int n = 5; - foo.Baz(&n); // Should return 5 and change n to 6. -``` - -## Writing New Polymorphic Actions ## - -The previous recipe showed you how to define your own action. This is -all good, except that you need to know the type of the function in -which the action will be used. Sometimes that can be a problem. For -example, if you want to use the action in functions with _different_ -types (e.g. like `Return()` and `SetArgPointee()`). - -If an action can be used in several types of mock functions, we say -it's _polymorphic_. The `MakePolymorphicAction()` function template -makes it easy to define such an action: - -``` -namespace testing { - -template -PolymorphicAction MakePolymorphicAction(const Impl& impl); - -} // namespace testing -``` - -As an example, let's define an action that returns the second argument -in the mock function's argument list. The first step is to define an -implementation class: - -``` -class ReturnSecondArgumentAction { - public: - template - Result Perform(const ArgumentTuple& args) const { - // To get the i-th (0-based) argument, use tr1::get(args). - return tr1::get<1>(args); - } -}; -``` - -This implementation class does _not_ need to inherit from any -particular class. What matters is that it must have a `Perform()` -method template. This method template takes the mock function's -arguments as a tuple in a **single** argument, and returns the result of -the action. It can be either `const` or not, but must be invokable -with exactly one template argument, which is the result type. In other -words, you must be able to call `Perform(args)` where `R` is the -mock function's return type and `args` is its arguments in a tuple. - -Next, we use `MakePolymorphicAction()` to turn an instance of the -implementation class into the polymorphic action we need. It will be -convenient to have a wrapper for this: - -``` -using ::testing::MakePolymorphicAction; -using ::testing::PolymorphicAction; - -PolymorphicAction ReturnSecondArgument() { - return MakePolymorphicAction(ReturnSecondArgumentAction()); -} -``` - -Now, you can use this polymorphic action the same way you use the -built-in ones: - -``` -using ::testing::_; - -class MockFoo : public Foo { - public: - MOCK_METHOD2(DoThis, int(bool flag, int n)); - MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); -}; -... - - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(ReturnSecondArgument()); - EXPECT_CALL(foo, DoThat(_, _, _)) - .WillOnce(ReturnSecondArgument()); - ... - foo.DoThis(true, 5); // Will return 5. - foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". -``` - -## Teaching Google Mock How to Print Your Values ## - -When an uninteresting or unexpected call occurs, Google Mock prints the -argument values and the stack trace to help you debug. Assertion -macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in -question when the assertion fails. Google Mock and Google Test do this using -Google Test's user-extensible value printer. - -This printer knows how to print built-in C++ types, native arrays, STL -containers, and any type that supports the `<<` operator. For other -types, it prints the raw bytes in the value and hopes that you the -user can figure it out. -[Google Test's advanced guide](http://code.google.com/p/googletest/wiki/AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) -explains how to extend the printer to do a better job at -printing your particular type than to dump the bytes. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_7/Documentation.md b/src/libtoast/gtest/googlemock/docs/v1_7/Documentation.md deleted file mode 100644 index d9181f28e..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_7/Documentation.md +++ /dev/null @@ -1,12 +0,0 @@ -This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** -- **if you use a released version of Google Mock, please read the documentation for that specific version instead.** - - * [ForDummies](V1_7_ForDummies.md) -- start here if you are new to Google Mock. - * [CheatSheet](V1_7_CheatSheet.md) -- a quick reference. - * [CookBook](V1_7_CookBook.md) -- recipes for doing various tasks using Google Mock. - * [FrequentlyAskedQuestions](V1_7_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. - -To contribute code to Google Mock, read: - - * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. - * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_7/ForDummies.md b/src/libtoast/gtest/googlemock/docs/v1_7/ForDummies.md deleted file mode 100644 index ee03c5b98..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_7/ForDummies.md +++ /dev/null @@ -1,439 +0,0 @@ - - -(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_7_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) - -# What Is Google C++ Mocking Framework? # -When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). - -**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: - - * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. - * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. - -If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. - -**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. - -Using Google Mock involves three basic steps: - - 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; - 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; - 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. - -# Why Google Mock? # -While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: - - * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. - * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. - * The knowledge you gained from using one mock doesn't transfer to the next. - -In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. - -Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: - - * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". - * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). - * Your tests are brittle as some resources they use are unreliable (e.g. the network). - * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. - * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. - * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. - -We encourage you to use Google Mock as: - - * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! - * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. - -# Getting Started # -Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. - -# A Case for Mock Turtles # -Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: - -``` -class Turtle { - ... - virtual ~Turtle() {} - virtual void PenUp() = 0; - virtual void PenDown() = 0; - virtual void Forward(int distance) = 0; - virtual void Turn(int degrees) = 0; - virtual void GoTo(int x, int y) = 0; - virtual int GetX() const = 0; - virtual int GetY() const = 0; -}; -``` - -(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) - -You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. - -Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. - -# Writing the Mock Class # -If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) - -## How to Define It ## -Using the `Turtle` interface as example, here are the simple steps you need to follow: - - 1. Derive a class `MockTurtle` from `Turtle`. - 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. - 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. - 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). - 1. Repeat until all virtual functions you want to mock are done. - -After the process, you should have something like: - -``` -#include "gmock/gmock.h" // Brings in Google Mock. -class MockTurtle : public Turtle { - public: - ... - MOCK_METHOD0(PenUp, void()); - MOCK_METHOD0(PenDown, void()); - MOCK_METHOD1(Forward, void(int distance)); - MOCK_METHOD1(Turn, void(int degrees)); - MOCK_METHOD2(GoTo, void(int x, int y)); - MOCK_CONST_METHOD0(GetX, int()); - MOCK_CONST_METHOD0(GetY, int()); -}; -``` - -You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. - -**Tip:** If even this is too much work for you, you'll find the -`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line -tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, -and it will print the definition of the mock class for you. Due to the -complexity of the C++ language, this script may not always work, but -it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). - -## Where to Put It ## -When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) - -So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. - -Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. - -# Using Mocks in Tests # -Once you have a mock class, using it is easy. The typical work flow is: - - 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). - 1. Create some mock objects. - 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). - 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. - 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. - -Here's an example: - -``` -#include "path/to/mock-turtle.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -using ::testing::AtLeast; // #1 - -TEST(PainterTest, CanDrawSomething) { - MockTurtle turtle; // #2 - EXPECT_CALL(turtle, PenDown()) // #3 - .Times(AtLeast(1)); - - Painter painter(&turtle); // #4 - - EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); -} // #5 - -int main(int argc, char** argv) { - // The following line must be executed to initialize Google Mock - // (and Google Test) before running the tests. - ::testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: - -``` -path/to/my_test.cc:119: Failure -Actual function call count doesn't match this expectation: -Actually: never called; -Expected: called at least once. -``` - -**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. - -**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. - -**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. - -This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. - -Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. - -## Using Google Mock with Any Testing Framework ## -If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or -[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: -``` -int main(int argc, char** argv) { - // The following line causes Google Mock to throw an exception on failure, - // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = true; - ::testing::InitGoogleMock(&argc, argv); - ... whatever your testing framework requires ... -} -``` - -This approach has a catch: it makes Google Mock throw an exception -from a mock object's destructor sometimes. With some compilers, this -sometimes causes the test program to crash. You'll still be able to -notice that the test has failed, but it's not a graceful failure. - -A better solution is to use Google Test's -[event listener API](http://code.google.com/p/googletest/wiki/AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) -to report a test failure to your testing framework properly. You'll need to -implement the `OnTestPartResult()` method of the event listener interface, but it -should be straightforward. - -If this turns out to be too much work, we suggest that you stick with -Google Test, which works with Google Mock seamlessly (in fact, it is -technically part of Google Mock.). If there is a reason that you -cannot use Google Test, please let us know. - -# Setting Expectations # -The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." - -## General Syntax ## -In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: - -``` -EXPECT_CALL(mock_object, method(matchers)) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) - -The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. - -This syntax is designed to make an expectation read like English. For example, you can probably guess that - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .Times(5) - .WillOnce(Return(100)) - .WillOnce(Return(150)) - .WillRepeatedly(Return(200)); -``` - -says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). - -**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. - -## Matchers: What Arguments Do We Expect? ## -When a mock function takes arguments, we must specify what arguments we are expecting; for example: - -``` -// Expects the turtle to move forward by 100 units. -EXPECT_CALL(turtle, Forward(100)); -``` - -Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": - -``` -using ::testing::_; -... -// Expects the turtle to move forward. -EXPECT_CALL(turtle, Forward(_)); -``` - -`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. - -A list of built-in matchers can be found in the [CheatSheet](V1_7_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: - -``` -using ::testing::Ge;... -EXPECT_CALL(turtle, Forward(Ge(100))); -``` - -This checks that the turtle will be told to go forward by at least 100 units. - -## Cardinalities: How Many Times Will It Be Called? ## -The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. - -An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. - -We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_7_CheatSheet.md). - -The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: - - * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. - * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. - * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. - -**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? - -## Actions: What Should It Do? ## -Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. - -First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. - -Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillOnce(Return(300)); -``` - -This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillRepeatedly(Return(300)); -``` - -says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. - -Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). - -What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#Actions). - -**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: - -``` -int n = 100; -EXPECT_CALL(turtle, GetX()) -.Times(4) -.WillRepeatedly(Return(n++)); -``` - -Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_7_CookBook.md). - -Time for another quiz! What do you think the following means? - -``` -using ::testing::Return;... -EXPECT_CALL(turtle, GetY()) -.Times(4) -.WillOnce(Return(100)); -``` - -Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. - -## Using Multiple Expectations ## -So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. - -By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: - -``` -using ::testing::_;... -EXPECT_CALL(turtle, Forward(_)); // #1 -EXPECT_CALL(turtle, Forward(10)) // #2 - .Times(2); -``` - -If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. - -**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. - -## Ordered vs Unordered Calls ## -By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. - -Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: - -``` -using ::testing::InSequence;... -TEST(FooTest, DrawsLineSegment) { - ... - { - InSequence dummy; - - EXPECT_CALL(turtle, PenDown()); - EXPECT_CALL(turtle, Forward(100)); - EXPECT_CALL(turtle, PenUp()); - } - Foo(); -} -``` - -By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. - -In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. - -(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_7_CookBook#Expecting_Partially_Ordered_Calls.md).) - -## All Expectations Are Sticky (Unless Said Otherwise) ## -Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? - -After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): - -``` -using ::testing::_;... -EXPECT_CALL(turtle, GoTo(_, _)) // #1 - .Times(AnyNumber()); -EXPECT_CALL(turtle, GoTo(0, 0)) // #2 - .Times(2); -``` - -Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. - -This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). - -Simple? Let's see if you've really understood it: what does the following code say? - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)); -} -``` - -If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! - -One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: - -``` -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); -} -``` - -And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: - -``` -using ::testing::InSequence; -using ::testing::Return; -... -{ - InSequence s; - - for (int i = 1; i <= n; i++) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); - } -} -``` - -By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). - -## Uninteresting Calls ## -A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. - -In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. - -# What Now? # -Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. - -Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_7_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/docs/v1_7/FrequentlyAskedQuestions.md b/src/libtoast/gtest/googlemock/docs/v1_7/FrequentlyAskedQuestions.md deleted file mode 100644 index fa21233aa..000000000 --- a/src/libtoast/gtest/googlemock/docs/v1_7/FrequentlyAskedQuestions.md +++ /dev/null @@ -1,628 +0,0 @@ - - -Please send your questions to the -[googlemock](http://groups.google.com/group/googlemock) discussion -group. If you need help with compiler errors, make sure you have -tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. - -## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## - -In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods). - -## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## - -After version 1.4.0 of Google Mock was released, we had an idea on how -to make it easier to write matchers that can generate informative -messages efficiently. We experimented with this idea and liked what -we saw. Therefore we decided to implement it. - -Unfortunately, this means that if you have defined your own matchers -by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, -your definitions will no longer compile. Matchers defined using the -`MATCHER*` family of macros are not affected. - -Sorry for the hassle if your matchers are affected. We believe it's -in everyone's long-term interest to make this change sooner than -later. Fortunately, it's usually not hard to migrate an existing -matcher to the new API. Here's what you need to do: - -If you wrote your matcher like this: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` - -you'll need to change it to: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - ... -}; -``` -(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second -argument of type `MatchResultListener*`.) - -If you were also using `ExplainMatchResultTo()` to improve the matcher -message: -``` -// Old matcher definition that doesn't work with the lastest -// Google Mock. -using ::testing::MatcherInterface; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetFoo() > 5; - } - - virtual void ExplainMatchResultTo(MyType value, - ::std::ostream* os) const { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Foo property is " << value.GetFoo(); - } - ... -}; -``` - -you should move the logic of `ExplainMatchResultTo()` into -`MatchAndExplain()`, using the `MatchResultListener` argument where -the `::std::ostream` was used: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MatcherInterface; -using ::testing::MatchResultListener; -... -class MyWonderfulMatcher : public MatcherInterface { - public: - ... - virtual bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Foo property is " << value.GetFoo(); - return value.GetFoo() > 5; - } - ... -}; -``` - -If your matcher is defined using `MakePolymorphicMatcher()`: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you should rename the `Matches()` method to `MatchAndExplain()` and -add a `MatchResultListener*` argument (the same as what you need to do -for matchers defined by implementing `MatcherInterface`): -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -If your polymorphic matcher uses `ExplainMatchResultTo()` for better -failure messages: -``` -// Old matcher definition that doesn't work with the latest -// Google Mock. -using ::testing::MakePolymorphicMatcher; -... -class MyGreatMatcher { - public: - ... - bool Matches(MyType value) const { - // Returns true if value matches. - return value.GetBar() < 42; - } - ... -}; -void ExplainMatchResultTo(const MyGreatMatcher& matcher, - MyType value, - ::std::ostream* os) { - // Prints some helpful information to os to help - // a user understand why value matches (or doesn't match). - *os << "the Bar property is " << value.GetBar(); -} -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -you'll need to move the logic inside `ExplainMatchResultTo()` to -`MatchAndExplain()`: -``` -// New matcher definition that works with the latest Google Mock. -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -... -class MyGreatMatcher { - public: - ... - bool MatchAndExplain(MyType value, - MatchResultListener* listener) const { - // Returns true if value matches. - *listener << "the Bar property is " << value.GetBar(); - return value.GetBar() < 42; - } - ... -}; -... MakePolymorphicMatcher(MyGreatMatcher()) ... -``` - -For more information, you can read these -[two](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Monomorphic_Matchers) -[recipes](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Matchers) -from the cookbook. As always, you -are welcome to post questions on `googlemock@googlegroups.com` if you -need any help. - -## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## - -Google Mock works out of the box with Google Test. However, it's easy -to configure it to work with any testing framework of your choice. -[Here](http://code.google.com/p/googlemock/wiki/V1_7_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. - -## How am I supposed to make sense of these horrible template errors? ## - -If you are confused by the compiler errors gcc threw at you, -try consulting the _Google Mock Doctor_ tool first. What it does is to -scan stdin for gcc error messages, and spit out diagnoses on the -problems (we call them diseases) your code has. - -To "install", run command: -``` -alias gmd='/scripts/gmock_doctor.py' -``` - -To use it, do: -``` - 2>&1 | gmd -``` - -For example: -``` -make my_test 2>&1 | gmd -``` - -Or you can run `gmd` and copy-n-paste gcc's error messages to it. - -## Can I mock a variadic function? ## - -You cannot mock a variadic function (i.e. a function taking ellipsis -(`...`) arguments) directly in Google Mock. - -The problem is that in general, there is _no way_ for a mock object to -know how many arguments are passed to the variadic method, and what -the arguments' types are. Only the _author of the base class_ knows -the protocol, and we cannot look into his head. - -Therefore, to mock such a function, the _user_ must teach the mock -object how to figure out the number of arguments and their types. One -way to do it is to provide overloaded versions of the function. - -Ellipsis arguments are inherited from C and not really a C++ feature. -They are unsafe to use and don't work with arguments that have -constructors or destructors. Therefore we recommend to avoid them in -C++ as much as possible. - -## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## - -If you compile this using Microsoft Visual C++ 2005 SP1: -``` -class Foo { - ... - virtual void Bar(const int i) = 0; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD1(Bar, void(const int i)); -}; -``` -You may get the following warning: -``` -warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier -``` - -This is a MSVC bug. The same code compiles fine with gcc ,for -example. If you use Visual C++ 2008 SP1, you would get the warning: -``` -warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers -``` - -In C++, if you _declare_ a function with a `const` parameter, the -`const` modifier is _ignored_. Therefore, the `Foo` base class above -is equivalent to: -``` -class Foo { - ... - virtual void Bar(int i) = 0; // int or const int? Makes no difference. -}; -``` - -In fact, you can _declare_ Bar() with an `int` parameter, and _define_ -it with a `const int` parameter. The compiler will still match them -up. - -Since making a parameter `const` is meaningless in the method -_declaration_, we recommend to remove it in both `Foo` and `MockFoo`. -That should workaround the VC bug. - -Note that we are talking about the _top-level_ `const` modifier here. -If the function parameter is passed by pointer or reference, declaring -the _pointee_ or _referee_ as `const` is still meaningful. For -example, the following two declarations are _not_ equivalent: -``` -void Bar(int* p); // Neither p nor *p is const. -void Bar(const int* p); // p is not const, but *p is. -``` - -## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## - -We've noticed that when the `/clr` compiler flag is used, Visual C++ -uses 5~6 times as much memory when compiling a mock class. We suggest -to avoid `/clr` when compiling native C++ mocks. - -## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## - -You might want to run your test with -`--gmock_verbose=info`. This flag lets Google Mock print a trace -of every mock function call it receives. By studying the trace, -you'll gain insights on why the expectations you set are not met. - -## How can I assert that a function is NEVER called? ## - -``` -EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## - -When Google Mock detects a failure, it prints relevant information -(the mock function arguments, the state of relevant expectations, and -etc) to help the user debug. If another failure is detected, Google -Mock will do the same, including printing the state of relevant -expectations. - -Sometimes an expectation's state didn't change between two failures, -and you'll see the same description of the state twice. They are -however _not_ redundant, as they refer to _different points in time_. -The fact they are the same _is_ interesting information. - -## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## - -Does the class (hopefully a pure interface) you are mocking have a -virtual destructor? - -Whenever you derive from a base class, make sure its destructor is -virtual. Otherwise Bad Things will happen. Consider the following -code: - -``` -class Base { - public: - // Not virtual, but should be. - ~Base() { ... } - ... -}; - -class Derived : public Base { - public: - ... - private: - std::string value_; -}; - -... - Base* p = new Derived; - ... - delete p; // Surprise! ~Base() will be called, but ~Derived() will not - // - value_ is leaked. -``` - -By changing `~Base()` to virtual, `~Derived()` will be correctly -called when `delete p` is executed, and the heap checker -will be happy. - -## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## - -When people complain about this, often they are referring to code like: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. However, I have to write the expectations in the -// reverse order. This sucks big time!!! -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); -``` - -The problem is that they didn't pick the **best** way to express the test's -intent. - -By default, expectations don't have to be matched in _any_ particular -order. If you want them to match in a certain order, you need to be -explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's -easy to accidentally over-specify your tests, and we want to make it -harder to do so. - -There are two better ways to write the test spec. You could either -put the expectations in sequence: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. Using a sequence, we can write the expectations -// in their natural order. -{ - InSequence s; - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -} -``` - -or you can put the sequence of actions in the same expectation: - -``` -// foo.Bar() should be called twice, return 1 the first time, and return -// 2 the second time. -EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -``` - -Back to the original questions: why does Google Mock search the -expectations (and `ON_CALL`s) from back to front? Because this -allows a user to set up a mock's behavior for the common case early -(e.g. in the mock's constructor or the test fixture's set-up phase) -and customize it with more specific rules later. If Google Mock -searches from front to back, this very useful pattern won't be -possible. - -## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## - -When choosing between being neat and being safe, we lean toward the -latter. So the answer is that we think it's better to show the -warning. - -Often people write `ON_CALL`s in the mock object's -constructor or `SetUp()`, as the default behavior rarely changes from -test to test. Then in the test body they set the expectations, which -are often different for each test. Having an `ON_CALL` in the set-up -part of a test doesn't mean that the calls are expected. If there's -no `EXPECT_CALL` and the method is called, it's possibly an error. If -we quietly let the call go through without notifying the user, bugs -may creep in unnoticed. - -If, however, you are sure that the calls are OK, you can write - -``` -EXPECT_CALL(foo, Bar(_)) - .WillRepeatedly(...); -``` - -instead of - -``` -ON_CALL(foo, Bar(_)) - .WillByDefault(...); -``` - -This tells Google Mock that you do expect the calls and no warning should be -printed. - -Also, you can control the verbosity using the `--gmock_verbose` flag. -If you find the output too noisy when debugging, just choose a less -verbose level. - -## How can I delete the mock function's argument in an action? ## - -If you find yourself needing to perform some action that's not -supported by Google Mock directly, remember that you can define your own -actions using -[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Actions) or -[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Actions), -or you can write a stub function and invoke it using -[Invoke()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Functions_Methods_Functors). - -## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## - -What?! I think it's beautiful. :-) - -While which syntax looks more natural is a subjective matter to some -extent, Google Mock's syntax was chosen for several practical advantages it -has. - -Try to mock a function that takes a map as an argument: -``` -virtual int GetSize(const map& m); -``` - -Using the proposed syntax, it would be: -``` -MOCK_METHOD1(GetSize, int, const map& m); -``` - -Guess what? You'll get a compiler error as the compiler thinks that -`const map& m` are **two**, not one, arguments. To work -around this you can use `typedef` to give the map type a name, but -that gets in the way of your work. Google Mock's syntax avoids this -problem as the function's argument types are protected inside a pair -of parentheses: -``` -// This compiles fine. -MOCK_METHOD1(GetSize, int(const map& m)); -``` - -You still need a `typedef` if the return type contains an unprotected -comma, but that's much rarer. - -Other advantages include: - 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. - 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. - 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! - -## My code calls a static/global function. Can I mock it? ## - -You can, but you need to make some changes. - -In general, if you find yourself needing to mock a static function, -it's a sign that your modules are too tightly coupled (and less -flexible, less reusable, less testable, etc). You are probably better -off defining a small interface and call the function through that -interface, which then can be easily mocked. It's a bit of work -initially, but usually pays for itself quickly. - -This Google Testing Blog -[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) -says it excellently. Check it out. - -## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## - -I know it's not a question, but you get an answer for free any way. :-) - -With Google Mock, you can create mocks in C++ easily. And people might be -tempted to use them everywhere. Sometimes they work great, and -sometimes you may find them, well, a pain to use. So, what's wrong in -the latter case? - -When you write a test without using mocks, you exercise the code and -assert that it returns the correct value or that the system is in an -expected state. This is sometimes called "state-based testing". - -Mocks are great for what some call "interaction-based" testing: -instead of checking the system state at the very end, mock objects -verify that they are invoked the right way and report an error as soon -as it arises, giving you a handle on the precise context in which the -error was triggered. This is often more effective and economical to -do than state-based testing. - -If you are doing state-based testing and using a test double just to -simulate the real object, you are probably better off using a fake. -Using a mock in this case causes pain, as it's not a strong point for -mocks to perform complex actions. If you experience this and think -that mocks suck, you are just not using the right tool for your -problem. Or, you might be trying to solve the wrong problem. :-) - -## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## - -By all means, NO! It's just an FYI. - -What it means is that you have a mock function, you haven't set any -expectations on it (by Google Mock's rule this means that you are not -interested in calls to this function and therefore it can be called -any number of times), and it is called. That's OK - you didn't say -it's not OK to call the function! - -What if you actually meant to disallow this function to be called, but -forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While -one can argue that it's the user's fault, Google Mock tries to be nice and -prints you a note. - -So, when you see the message and believe that there shouldn't be any -uninteresting calls, you should investigate what's going on. To make -your life easier, Google Mock prints the function name and arguments -when an uninteresting call is encountered. - -## I want to define a custom action. Should I use Invoke() or implement the action interface? ## - -Either way is fine - you want to choose the one that's more convenient -for your circumstance. - -Usually, if your action is for a particular function type, defining it -using `Invoke()` should be easier; if your action can be used in -functions of different types (e.g. if you are defining -`Return(value)`), `MakePolymorphicAction()` is -easiest. Sometimes you want precise control on what types of -functions the action can be used in, and implementing -`ActionInterface` is the way to go here. See the implementation of -`Return()` in `include/gmock/gmock-actions.h` for an example. - -## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## - -You got this error as Google Mock has no idea what value it should return -when the mock method is called. `SetArgPointee()` says what the -side effect is, but doesn't say what the return value should be. You -need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. - -See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Side_Effects) for more details and an example. - - -## My question is not in your FAQ! ## - -If you cannot find the answer to your question in this FAQ, there are -some other resources you can use: - - 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), - 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), - 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). - -Please note that creating an issue in the -[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ -a good way to get your answer, as it is monitored infrequently by a -very small number of people. - -When asking a question, it's helpful to provide as much of the -following information as possible (people cannot help you if there's -not enough information in your question): - - * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), - * your operating system, - * the name and version of your compiler, - * the complete command line flags you give to your compiler, - * the complete compiler error messages (if the question is about compilation), - * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. \ No newline at end of file diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-actions.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-actions.h index b3f654af3..c785ad8ab 100644 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-actions.h +++ b/src/libtoast/gtest/googlemock/include/gmock/gmock-actions.h @@ -26,28 +26,129 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (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 Mock - a framework for writing C++ mock classes. // -// This file implements some commonly used actions. +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// Users can, however, define any local functors (e.g. a lambda) that +// can be used as actions. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' on +// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #ifndef _WIN32_WCE -# include +#include #endif #include +#include +#include #include +#include +#include +#include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" -#if GTEST_HAS_STD_TYPE_TRAITS_ // Defined by gtest-port.h via gmock-port.h. -#include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) #endif namespace testing { @@ -63,9 +164,6 @@ namespace testing { namespace internal { -template -class ActionAdaptor; - // BuiltInDefaultValueGetter::Get() returns a // default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. @@ -96,28 +194,14 @@ struct BuiltInDefaultValueGetter { template class BuiltInDefaultValue { public: -#if GTEST_HAS_STD_TYPE_TRAITS_ - // This function returns true iff type T has a built-in default value. - static bool Exists() { - return ::std::is_default_constructible::value; - } + // This function returns true if and only if type T has a built-in default + // value. + static bool Exists() { return ::std::is_default_constructible::value; } static T Get() { return BuiltInDefaultValueGetter< T, ::std::is_default_constructible::value>::Get(); } - -#else // GTEST_HAS_STD_TYPE_TRAITS_ - // This function returns true iff type T has a built-in default value. - static bool Exists() { - return false; - } - - static T Get() { - return BuiltInDefaultValueGetter::Get(); - } - -#endif // GTEST_HAS_STD_TYPE_TRAITS_ }; // This partial specialization says that we use the same built-in @@ -135,23 +219,20 @@ template class BuiltInDefaultValue { public: static bool Exists() { return true; } - static T* Get() { return NULL; } + static T* Get() { return nullptr; } }; // The following specializations define the default values for // specific types we care about. #define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ - template <> \ - class BuiltInDefaultValue { \ - public: \ - static bool Exists() { return true; } \ - static type Get() { return value; } \ + template <> \ + class BuiltInDefaultValue { \ + public: \ + static bool Exists() { return true; } \ + static type Get() { return value; } \ } GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT -#if GTEST_HAS_GLOBAL_STRING -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, ""); -#endif // GTEST_HAS_GLOBAL_STRING GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); @@ -172,17 +253,309 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); #undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ +// Partial implementations of metaprogramming types from the standard library +// not available in C++11. + +template +struct negation + // NOLINTNEXTLINE + : std::integral_constant {}; + +// Base case: with zero predicates the answer is always true. +template +struct conjunction : std::true_type {}; + +// With a single predicate, the answer is that predicate. +template +struct conjunction : P1 {}; + +// With multiple predicates the answer is the first predicate if that is false, +// and we recurse otherwise. +template +struct conjunction + : std::conditional, P1>::type {}; + +template +struct disjunction : std::false_type {}; + +template +struct disjunction : P1 {}; + +template +struct disjunction + // NOLINTNEXTLINE + : std::conditional, P1>::type {}; + +template +using void_t = void; + +// Detects whether an expression of type `From` can be implicitly converted to +// `To` according to [conv]. In C++17, [conv]/3 defines this as follows: +// +// An expression e can be implicitly converted to a type T if and only if +// the declaration T t=e; is well-formed, for some invented temporary +// variable t ([dcl.init]). +// +// [conv]/2 implies we can use function argument passing to detect whether this +// initialization is valid. +// +// Note that this is distinct from is_convertible, which requires this be valid: +// +// To test() { +// return declval(); +// } +// +// In particular, is_convertible doesn't give the correct answer when `To` and +// `From` are the same non-moveable type since `declval` will be an rvalue +// reference, defeating the guaranteed copy elision that would otherwise make +// this function work. +// +// REQUIRES: `From` is not cv void. +template +struct is_implicitly_convertible { + private: + // A function that accepts a parameter of type T. This can be called with type + // U successfully only if U is implicitly convertible to T. + template + static void Accept(T); + + // A function that creates a value of type T. + template + static T Make(); + + // An overload be selected when implicit conversion from T to To is possible. + template (Make()))> + static std::true_type TestImplicitConversion(int); + + // A fallback overload selected in all other cases. + template + static std::false_type TestImplicitConversion(...); + + public: + using type = decltype(TestImplicitConversion(0)); + static constexpr bool value = type::value; +}; + +// Like std::invoke_result_t from C++17, but works only for objects with call +// operators (not e.g. member function pointers, which we don't need specific +// support for in OnceAction because std::function deals with them). +template +using call_result_t = decltype(std::declval()(std::declval()...)); + +template +struct is_callable_r_impl : std::false_type {}; + +// Specialize the struct for those template arguments where call_result_t is +// well-formed. When it's not, the generic template above is chosen, resulting +// in std::false_type. +template +struct is_callable_r_impl>, R, F, Args...> + : std::conditional< + std::is_void::value, // + std::true_type, // + is_implicitly_convertible, R>>::type {}; + +// Like std::is_invocable_r from C++17, but works only for objects with call +// operators. See the note on call_result_t. +template +using is_callable_r = is_callable_r_impl; + +// Like std::as_const from C++17. +template +typename std::add_const::type& as_const(T& t) { + return t; +} + } // namespace internal +// Specialized for function types below. +template +class OnceAction; + +// An action that can only be used once. +// +// This is accepted by WillOnce, which doesn't require the underlying action to +// be copy-constructible (only move-constructible), and promises to invoke it as +// an rvalue reference. This allows the action to work with move-only types like +// std::move_only_function in a type-safe manner. +// +// For example: +// +// // Assume we have some API that needs to accept a unique pointer to some +// // non-copyable object Foo. +// void AcceptUniquePointer(std::unique_ptr foo); +// +// // We can define an action that provides a Foo to that API. Because It +// // has to give away its unique pointer, it must not be called more than +// // once, so its call operator is &&-qualified. +// struct ProvideFoo { +// std::unique_ptr foo; +// +// void operator()() && { +// AcceptUniquePointer(std::move(Foo)); +// } +// }; +// +// // This action can be used with WillOnce. +// EXPECT_CALL(mock, Call) +// .WillOnce(ProvideFoo{std::make_unique(...)}); +// +// // But a call to WillRepeatedly will fail to compile. This is correct, +// // since the action cannot correctly be used repeatedly. +// EXPECT_CALL(mock, Call) +// .WillRepeatedly(ProvideFoo{std::make_unique(...)}); +// +// A less-contrived example would be an action that returns an arbitrary type, +// whose &&-qualified call operator is capable of dealing with move-only types. +template +class OnceAction final { + private: + // True iff we can use the given callable type (or lvalue reference) directly + // via StdFunctionAdaptor. + template + using IsDirectlyCompatible = internal::conjunction< + // It must be possible to capture the callable in StdFunctionAdaptor. + std::is_constructible::type, Callable>, + // The callable must be compatible with our signature. + internal::is_callable_r::type, + Args...>>; + + // True iff we can use the given callable type via StdFunctionAdaptor once we + // ignore incoming arguments. + template + using IsCompatibleAfterIgnoringArguments = internal::conjunction< + // It must be possible to capture the callable in a lambda. + std::is_constructible::type, Callable>, + // The callable must be invocable with zero arguments, returning something + // convertible to Result. + internal::is_callable_r::type>>; + + public: + // Construct from a callable that is directly compatible with our mocked + // signature: it accepts our function type's arguments and returns something + // convertible to our result type. + template ::type>>, + IsDirectlyCompatible> // + ::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + : function_(StdFunctionAdaptor::type>( + {}, std::forward(callable))) {} + + // As above, but for a callable that ignores the mocked function's arguments. + template ::type>>, + // Exclude callables for which the overload above works. + // We'd rather provide the arguments if possible. + internal::negation>, + IsCompatibleAfterIgnoringArguments>::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + // Call the constructor above with a callable + // that ignores the input arguments. + : OnceAction(IgnoreIncomingArguments::type>{ + std::forward(callable)}) {} + + // We are naturally copyable because we store only an std::function, but + // semantically we should not be copyable. + OnceAction(const OnceAction&) = delete; + OnceAction& operator=(const OnceAction&) = delete; + OnceAction(OnceAction&&) = default; + + // Invoke the underlying action callable with which we were constructed, + // handing it the supplied arguments. + Result Call(Args... args) && { + return function_(std::forward(args)...); + } + + private: + // An adaptor that wraps a callable that is compatible with our signature and + // being invoked as an rvalue reference so that it can be used as an + // StdFunctionAdaptor. This throws away type safety, but that's fine because + // this is only used by WillOnce, which we know calls at most once. + // + // Once we have something like std::move_only_function from C++23, we can do + // away with this. + template + class StdFunctionAdaptor final { + public: + // A tag indicating that the (otherwise universal) constructor is accepting + // the callable itself, instead of e.g. stealing calls for the move + // constructor. + struct CallableTag final {}; + + template + explicit StdFunctionAdaptor(CallableTag, F&& callable) + : callable_(std::make_shared(std::forward(callable))) {} + + // Rather than explicitly returning Result, we return whatever the wrapped + // callable returns. This allows for compatibility with existing uses like + // the following, when the mocked function returns void: + // + // EXPECT_CALL(mock_fn_, Call) + // .WillOnce([&] { + // [...] + // return 0; + // }); + // + // Such a callable can be turned into std::function. If we use an + // explicit return type of Result here then it *doesn't* work with + // std::function, because we'll get a "void function should not return a + // value" error. + // + // We need not worry about incompatible result types because the SFINAE on + // OnceAction already checks this for us. std::is_invocable_r_v itself makes + // the same allowance for void result types. + template + internal::call_result_t operator()( + ArgRefs&&... args) const { + return std::move(*callable_)(std::forward(args)...); + } + + private: + // We must put the callable on the heap so that we are copyable, which + // std::function needs. + std::shared_ptr callable_; + }; + + // An adaptor that makes a callable that accepts zero arguments callable with + // our mocked arguments. + template + struct IgnoreIncomingArguments { + internal::call_result_t operator()(Args&&...) { + return std::move(callable)(); + } + + Callable callable; + }; + + std::function function_; +}; + // When an unexpected function call is encountered, Google Mock will // let it return a default value if the user has specified one for its // return type, or if the return type has a built-in default value; @@ -218,11 +591,11 @@ class DefaultValue { // Unsets the default value for type T. static void Clear() { delete producer_; - producer_ = NULL; + producer_ = nullptr; } - // Returns true iff the user has set the default value for type T. - static bool IsSet() { return producer_ != NULL; } + // Returns true if and only if the user has set the default value for type T. + static bool IsSet() { return producer_ != nullptr; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. @@ -234,8 +607,8 @@ class DefaultValue { // otherwise returns the built-in default value. Requires that Exists() // is true, which ensures that the return value is well-defined. static T Get() { - return producer_ == NULL ? - internal::BuiltInDefaultValue::Get() : producer_->Produce(); + return producer_ == nullptr ? internal::BuiltInDefaultValue::Get() + : producer_->Produce(); } private: @@ -248,22 +621,24 @@ class DefaultValue { class FixedValueProducer : public ValueProducer { public: explicit FixedValueProducer(T value) : value_(value) {} - virtual T Produce() { return value_; } + T Produce() override { return value_; } private: const T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer); + FixedValueProducer(const FixedValueProducer&) = delete; + FixedValueProducer& operator=(const FixedValueProducer&) = delete; }; class FactoryValueProducer : public ValueProducer { public: explicit FactoryValueProducer(FactoryFunction factory) : factory_(factory) {} - virtual T Produce() { return factory_(); } + T Produce() override { return factory_(); } private: const FactoryFunction factory_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer); + FactoryValueProducer(const FactoryValueProducer&) = delete; + FactoryValueProducer& operator=(const FactoryValueProducer&) = delete; }; static ValueProducer* producer_; @@ -280,12 +655,10 @@ class DefaultValue { } // Unsets the default value for type T&. - static void Clear() { - address_ = NULL; - } + static void Clear() { address_ = nullptr; } - // Returns true iff the user has set the default value for type T&. - static bool IsSet() { return address_ != NULL; } + // Returns true if and only if the user has set the default value for type T&. + static bool IsSet() { return address_ != nullptr; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. @@ -297,8 +670,8 @@ class DefaultValue { // otherwise returns the built-in default value if there is one; // otherwise aborts the process. static T& Get() { - return address_ == NULL ? - internal::BuiltInDefaultValue::Get() : *address_; + return address_ == nullptr ? internal::BuiltInDefaultValue::Get() + : *address_; } private: @@ -316,11 +689,11 @@ class DefaultValue { // Points to the user-set default value for type T. template -typename DefaultValue::ValueProducer* DefaultValue::producer_ = NULL; +typename DefaultValue::ValueProducer* DefaultValue::producer_ = nullptr; // Points to the user-set default value for type T&. template -T* DefaultValue::address_ = NULL; +T* DefaultValue::address_ = nullptr; // Implement this interface to define an action for function type F. template @@ -339,44 +712,73 @@ class ActionInterface { virtual Result Perform(const ArgumentTuple& args) = 0; private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); + ActionInterface(const ActionInterface&) = delete; + ActionInterface& operator=(const ActionInterface&) = delete; }; -// An Action is a copyable and IMMUTABLE (except by assignment) -// object that represents an action to be taken when a mock function -// of type F is called. The implementation of Action is just a -// linked_ptr to const ActionInterface, so copying is fairly cheap. -// Don't inherit from Action! -// -// You can view an object implementing ActionInterface as a -// concrete action (including its current state), and an Action -// object as a handle to it. template -class Action { +class Action; + +// An Action is a copyable and IMMUTABLE (except by assignment) +// object that represents an action to be taken when a mock function of type +// R(Args...) is called. The implementation of Action is just a +// std::shared_ptr to const ActionInterface. Don't inherit from Action! You +// can view an object implementing ActionInterface as a concrete action +// (including its current state), and an Action object as a handle to it. +template +class Action { + private: + using F = R(Args...); + + // Adapter class to allow constructing Action from a legacy ActionInterface. + // New code should create Actions from functors instead. + struct ActionAdapter { + // Adapter must be copyable to satisfy std::function requirements. + ::std::shared_ptr> impl_; + + template + typename internal::Function::Result operator()(InArgs&&... args) { + return impl_->Perform( + ::std::forward_as_tuple(::std::forward(args)...)); + } + }; + + template + using IsCompatibleFunctor = std::is_constructible, G>; + public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; // Constructs a null Action. Needed for storing Action objects in // STL containers. - Action() : impl_(NULL) {} - - // Constructs an Action from its implementation. A NULL impl is - // used to represent the "do-default" action. - explicit Action(ActionInterface* impl) : impl_(impl) {} + Action() {} + + // Construct an Action from a specified callable. + // This cannot take std::function directly, because then Action would not be + // directly constructible from lambda (it would require two conversions). + template < + typename G, + typename = typename std::enable_if, std::is_constructible, + G>>::value>::type> + Action(G&& fun) { // NOLINT + Init(::std::forward(fun), IsCompatibleFunctor()); + } - // Copy constructor. - Action(const Action& action) : impl_(action.impl_) {} + // Constructs an Action from its implementation. + explicit Action(ActionInterface* impl) + : fun_(ActionAdapter{::std::shared_ptr>(impl)}) {} // This constructor allows us to turn an Action object into an // Action, as long as F's arguments can be implicitly converted - // to Func's and Func's return type can be implicitly converted to - // F's. + // to Func's and Func's return type can be implicitly converted to F's. template - explicit Action(const Action& action); + Action(const Action& action) // NOLINT + : fun_(action.fun_) {} - // Returns true iff this is the DoDefault() action. - bool IsDoDefault() const { return impl_.get() == NULL; } + // Returns true if and only if this is the DoDefault() action. + bool IsDoDefault() const { return fun_ == nullptr; } // Performs the action. Note that this method is const even though // the corresponding method in ActionInterface is not. The reason @@ -384,22 +786,57 @@ class Action { // another concrete action, not that the concrete action it binds to // cannot change state. (Think of the difference between a const // pointer and a pointer to const.) - Result Perform(const ArgumentTuple& args) const { - internal::Assert( - !IsDoDefault(), __FILE__, __LINE__, - "You are using DoDefault() inside a composite action like " - "DoAll() or WithArgs(). This is not supported for technical " - "reasons. Please instead spell out the default action, or " - "assign the default action to an Action variable and use " - "the variable in various places."); - return impl_->Perform(args); + Result Perform(ArgumentTuple args) const { + if (IsDoDefault()) { + internal::IllegalDoDefault(__FILE__, __LINE__); + } + return internal::Apply(fun_, ::std::move(args)); + } + + // An action can be used as a OnceAction, since it's obviously safe to call it + // once. + operator OnceAction() const { // NOLINT + // Return a OnceAction-compatible callable that calls Perform with the + // arguments it is provided. We could instead just return fun_, but then + // we'd need to handle the IsDoDefault() case separately. + struct OA { + Action action; + + R operator()(Args... args) && { + return action.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{*this}; } private: - template - friend class internal::ActionAdaptor; + template + friend class Action; + + template + void Init(G&& g, ::std::true_type) { + fun_ = ::std::forward(g); + } + + template + void Init(G&& g, ::std::false_type) { + fun_ = IgnoreArgs::type>{::std::forward(g)}; + } + + template + struct IgnoreArgs { + template + Result operator()(const InArgs&...) const { + return function_impl(); + } - internal::linked_ptr > impl_; + FunctionImpl function_impl; + }; + + // fun_ is an empty function if and only if this is the DoDefault() action. + ::std::function fun_; }; // The PolymorphicAction class template makes it easy to implement a @@ -414,7 +851,7 @@ class Action { // template // Result Perform(const ArgumentTuple& args) const { // // Processes the arguments and returns a result, using -// // tr1::get(args) to get the N-th (0-based) argument in the tuple. +// // std::get(args) to get the N-th (0-based) argument in the tuple. // } // ... // }; @@ -442,19 +879,15 @@ class PolymorphicAction { explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - virtual Result Perform(const ArgumentTuple& args) { + Result Perform(const ArgumentTuple& args) override { return impl_.template Perform(args); } private: Impl impl_; - - GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); }; Impl impl_; - - GTEST_DISALLOW_ASSIGN_(PolymorphicAction); }; // Creates an Action from its implementation and returns it. The @@ -478,145 +911,206 @@ inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { namespace internal { -// Allows an Action object to pose as an Action, as long as F2 -// and F1 are compatible. -template -class ActionAdaptor : public ActionInterface { - public: - typedef typename internal::Function::Result Result; - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - explicit ActionAdaptor(const Action& from) : impl_(from.impl_) {} - - virtual Result Perform(const ArgumentTuple& args) { - return impl_->Perform(args); - } - - private: - const internal::linked_ptr > impl_; - - GTEST_DISALLOW_ASSIGN_(ActionAdaptor); -}; - // Helper struct to specialize ReturnAction to execute a move instead of a copy // on return. Useful for move-only types, but could be used on any type. template struct ByMoveWrapper { - explicit ByMoveWrapper(T value) : payload(internal::move(value)) {} + explicit ByMoveWrapper(T value) : payload(std::move(value)) {} T payload; }; -// Implements the polymorphic Return(x) action, which can be used in -// any function that returns the type of x, regardless of the argument -// types. -// -// Note: The value passed into Return must be converted into -// Function::Result when this action is cast to Action rather than -// when that action is performed. This is important in scenarios like -// -// MOCK_METHOD1(Method, T(U)); -// ... -// { -// Foo foo; -// X x(&foo); -// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x)); -// } -// -// In the example above the variable x holds reference to foo which leaves -// scope and gets destroyed. If copying X just copies a reference to foo, -// that copy will be left with a hanging reference. If conversion to T -// makes a copy of foo, the above code is safe. To support that scenario, we -// need to make sure that the type conversion happens inside the EXPECT_CALL -// statement, and conversion of the result of Return to Action is a -// good place for that. -// +// The general implementation of Return(R). Specializations follow below. template -class ReturnAction { +class ReturnAction final { public: - // Constructs a ReturnAction object from the value to be returned. - // 'value' is passed by value instead of by const reference in order - // to allow Return("string literal") to compile. - explicit ReturnAction(R value) : value_(new R(internal::move(value))) {} + explicit ReturnAction(R value) : value_(std::move(value)) {} + + template >, // + negation>, // + std::is_convertible, // + std::is_move_constructible>::value>::type> + operator OnceAction() && { // NOLINT + return Impl(std::move(value_)); + } - // This template type conversion operator allows Return(x) to be - // used in ANY function that returns x's type. - template - operator Action() const { - // Assert statement belongs here because this is the best place to verify - // conditions on F. It produces the clearest error messages - // in most compilers. - // Impl really belongs in this scope as a local class but can't - // because MSVC produces duplicate symbols in different translation units - // in this case. Until MS fixes that bug we put Impl into the class scope - // and put the typedef both here (for use in assert statement) and - // in the Impl class. But both definitions must be the same. - typedef typename Function::Result Result; - GTEST_COMPILE_ASSERT_( - !is_reference::value, - use_ReturnRef_instead_of_Return_to_return_a_reference); - return Action(new Impl(value_)); + template >, // + negation>, // + std::is_convertible, // + std::is_copy_constructible>::value>::type> + operator Action() const { // NOLINT + return Impl(value_); } private: - // Implements the Return(x) action for a particular function type F. - template - class Impl : public ActionInterface { + // Implements the Return(x) action for a mock function that returns type U. + template + class Impl final { public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; + // The constructor used when the return value is allowed to move from the + // input value (i.e. we are converting to OnceAction). + explicit Impl(R&& input_value) + : state_(new State(std::move(input_value))) {} - // The implicit cast is necessary when Result has more than one - // single-argument constructor (e.g. Result is std::vector) and R - // has a type conversion operator template. In that case, value_(value) - // won't compile as the compiler doesn't known which constructor of - // Result to call. ImplicitCast_ forces the compiler to convert R to - // Result without considering explicit constructors, thus resolving the - // ambiguity. value_ is then initialized using its copy constructor. - explicit Impl(const linked_ptr& value) - : value_before_cast_(*value), - value_(ImplicitCast_(value_before_cast_)) {} + // The constructor used when the return value is not allowed to move from + // the input value (i.e. we are converting to Action). + explicit Impl(const R& input_value) : state_(new State(input_value)) {} - virtual Result Perform(const ArgumentTuple&) { return value_; } + U operator()() && { return std::move(state_->value); } + U operator()() const& { return state_->value; } private: - GTEST_COMPILE_ASSERT_(!is_reference::value, - Result_cannot_be_a_reference_type); - // We save the value before casting just in case it is being cast to a - // wrapper type. - R value_before_cast_; - Result value_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); + // We put our state on the heap so that the compiler-generated copy/move + // constructors work correctly even when U is a reference-like type. This is + // necessary only because we eagerly create State::value (see the note on + // that symbol for details). If we instead had only the input value as a + // member then the default constructors would work fine. + // + // For example, when R is std::string and U is std::string_view, value is a + // reference to the string backed by input_value. The copy constructor would + // copy both, so that we wind up with a new input_value object (with the + // same contents) and a reference to the *old* input_value object rather + // than the new one. + struct State { + explicit State(const R& input_value_in) + : input_value(input_value_in), + // Make an implicit conversion to Result before initializing the U + // object we store, avoiding calling any explicit constructor of U + // from R. + // + // This simulates the language rules: a function with return type U + // that does `return R()` requires R to be implicitly convertible to + // U, and uses that path for the conversion, even U Result has an + // explicit constructor from R. + value(ImplicitCast_(internal::as_const(input_value))) {} + + // As above, but for the case where we're moving from the ReturnAction + // object because it's being used as a OnceAction. + explicit State(R&& input_value_in) + : input_value(std::move(input_value_in)), + // For the same reason as above we make an implicit conversion to U + // before initializing the value. + // + // Unlike above we provide the input value as an rvalue to the + // implicit conversion because this is a OnceAction: it's fine if it + // wants to consume the input value. + value(ImplicitCast_(std::move(input_value))) {} + + // A copy of the value originally provided by the user. We retain this in + // addition to the value of the mock function's result type below in case + // the latter is a reference-like type. See the std::string_view example + // in the documentation on Return. + R input_value; + + // The value we actually return, as the type returned by the mock function + // itself. + // + // We eagerly initialize this here, rather than lazily doing the implicit + // conversion automatically each time Perform is called, for historical + // reasons: in 2009-11, commit a070cbd91c (Google changelist 13540126) + // made the Action conversion operator eagerly convert the R value to + // U, but without keeping the R alive. This broke the use case discussed + // in the documentation for Return, making reference-like types such as + // std::string_view not safe to use as U where the input type R is a + // value-like type such as std::string. + // + // The example the commit gave was not very clear, nor was the issue + // thread (https://github.com/google/googlemock/issues/86), but it seems + // the worry was about reference-like input types R that flatten to a + // value-like type U when being implicitly converted. An example of this + // is std::vector::reference, which is often a proxy type with an + // reference to the underlying vector: + // + // // Helper method: have the mock function return bools according + // // to the supplied script. + // void SetActions(MockFunction& mock, + // const std::vector& script) { + // for (size_t i = 0; i < script.size(); ++i) { + // EXPECT_CALL(mock, Call(i)).WillOnce(Return(script[i])); + // } + // } + // + // TEST(Foo, Bar) { + // // Set actions using a temporary vector, whose operator[] + // // returns proxy objects that references that will be + // // dangling once the call to SetActions finishes and the + // // vector is destroyed. + // MockFunction mock; + // SetActions(mock, {false, true}); + // + // EXPECT_FALSE(mock.AsStdFunction()(0)); + // EXPECT_TRUE(mock.AsStdFunction()(1)); + // } + // + // This eager conversion helps with a simple case like this, but doesn't + // fully make these types work in general. For example the following still + // uses a dangling reference: + // + // TEST(Foo, Baz) { + // MockFunction()> mock; + // + // // Return the same vector twice, and then the empty vector + // // thereafter. + // auto action = Return(std::initializer_list{ + // "taco", "burrito", + // }); + // + // EXPECT_CALL(mock, Call) + // .WillOnce(action) + // .WillOnce(action) + // .WillRepeatedly(Return(std::vector{})); + // + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), IsEmpty()); + // } + // + U value; + }; + + const std::shared_ptr state_; }; - // Partially specialize for ByMoveWrapper. This version of ReturnAction will - // move its contents instead. - template - class Impl, F> : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; + R value_; +}; - explicit Impl(const linked_ptr& wrapper) - : performed_(false), wrapper_(wrapper) {} +// A specialization of ReturnAction when R is ByMoveWrapper for some T. +// +// This version applies the type system-defeating hack of moving from T even in +// the const call operator, checking at runtime that it isn't called more than +// once, since the user has declared their intent to do so by using ByMove. +template +class ReturnAction> final { + public: + explicit ReturnAction(ByMoveWrapper wrapper) + : state_(new State(std::move(wrapper.payload))) {} - virtual Result Perform(const ArgumentTuple&) { - GTEST_CHECK_(!performed_) - << "A ByMove() action should only be performed once."; - performed_ = true; - return internal::move(wrapper_->payload); - } + T operator()() const { + GTEST_CHECK_(!state_->called) + << "A ByMove() action must be performed at most once."; - private: - bool performed_; - const linked_ptr wrapper_; + state_->called = true; + return std::move(state_->value); + } - GTEST_DISALLOW_ASSIGN_(Impl); - }; + private: + // We store our state on the heap so that we are copyable as required by + // Action, despite the fact that we are stateful and T may not be copyable. + struct State { + explicit State(T&& value_in) : value(std::move(value_in)) {} - const linked_ptr value_; + T value; + bool called = false; + }; - GTEST_DISALLOW_ASSIGN_(ReturnAction); + const std::shared_ptr state_; }; // Implements the ReturnNull() action. @@ -627,13 +1121,7 @@ class ReturnNullAction { // pointer type on compile time. template static Result Perform(const ArgumentTuple&) { -#if GTEST_LANG_CXX11 return nullptr; -#else - GTEST_COMPILE_ASSERT_(internal::is_pointer::value, - ReturnNull_can_be_used_to_return_a_pointer_only); - return NULL; -#endif // GTEST_LANG_CXX11 } }; @@ -643,7 +1131,7 @@ class ReturnVoidAction { // Allows Return() to be used in any void-returning function. template static void Perform(const ArgumentTuple&) { - CompileAssertTypesEqual(); + static_assert(std::is_void::value, "Result should be void."); } }; @@ -664,8 +1152,8 @@ class ReturnRefAction { // Asserts that the function return type is a reference. This // catches the user error of using ReturnRef(x) when Return(x) // should be used, and generates some helpful error message. - GTEST_COMPILE_ASSERT_(internal::is_reference::value, - use_Return_instead_of_ReturnRef_to_return_a_value); + static_assert(std::is_reference::value, + "use Return instead of ReturnRef to return a value"); return Action(new Impl(ref_)); } @@ -679,19 +1167,13 @@ class ReturnRefAction { explicit Impl(T& ref) : ref_(ref) {} // NOLINT - virtual Result Perform(const ArgumentTuple&) { - return ref_; - } + Result Perform(const ArgumentTuple&) override { return ref_; } private: T& ref_; - - GTEST_DISALLOW_ASSIGN_(Impl); }; T& ref_; - - GTEST_DISALLOW_ASSIGN_(ReturnRefAction); }; // Implements the polymorphic ReturnRefOfCopy(x) action, which can be @@ -712,9 +1194,8 @@ class ReturnRefOfCopyAction { // Asserts that the function return type is a reference. This // catches the user error of using ReturnRefOfCopy(x) when Return(x) // should be used, and generates some helpful error message. - GTEST_COMPILE_ASSERT_( - internal::is_reference::value, - use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); + static_assert(std::is_reference::value, + "use Return instead of ReturnRefOfCopy to return a value"); return Action(new Impl(value_)); } @@ -728,19 +1209,43 @@ class ReturnRefOfCopyAction { explicit Impl(const T& value) : value_(value) {} // NOLINT - virtual Result Perform(const ArgumentTuple&) { - return value_; - } + Result Perform(const ArgumentTuple&) override { return value_; } private: T value_; - - GTEST_DISALLOW_ASSIGN_(Impl); }; const T value_; +}; + +// Implements the polymorphic ReturnRoundRobin(v) action, which can be +// used in any function that returns the element_type of v. +template +class ReturnRoundRobinAction { + public: + explicit ReturnRoundRobinAction(std::vector values) { + GTEST_CHECK_(!values.empty()) + << "ReturnRoundRobin requires at least one element."; + state_->values = std::move(values); + } - GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); + template + T operator()(Args&&...) const { + return state_->Next(); + } + + private: + struct State { + T Next() { + T ret_val = values[i++]; + if (i == values.size()) i = 0; + return ret_val; + } + + std::vector values; + size_t i = 0; + }; + std::shared_ptr state_ = std::make_shared(); }; // Implements the polymorphic DoDefault() action. @@ -749,7 +1254,9 @@ class DoDefaultAction { // This template type conversion operator allows DoDefault() to be // used in any function. template - operator Action() const { return Action(NULL); } + operator Action() const { + return Action(); + } // NOLINT }; // Implements the Assign action to set a given pointer referent to a @@ -767,8 +1274,6 @@ class AssignAction { private: T1* const ptr_; const T2 value_; - - GTEST_DISALLOW_ASSIGN_(AssignAction); }; #if !GTEST_OS_WINDOWS_MOBILE @@ -779,8 +1284,7 @@ template class SetErrnoAndReturnAction { public: SetErrnoAndReturnAction(int errno_value, T result) - : errno_(errno_value), - result_(result) {} + : errno_(errno_value), result_(result) {} template Result Perform(const ArgumentTuple& /* args */) const { errno = errno_; @@ -790,99 +1294,64 @@ class SetErrnoAndReturnAction { private: const int errno_; const T result_; - - GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction); }; #endif // !GTEST_OS_WINDOWS_MOBILE // Implements the SetArgumentPointee(x) action for any function -// whose N-th argument (0-based) is a pointer to x's type. The -// template parameter kIsProto is true iff type A is ProtocolMessage, -// proto2::Message, or a sub-class of those. -template -class SetArgumentPointeeAction { - public: - // Constructs an action that sets the variable pointed to by the - // N-th function argument to 'value'. - explicit SetArgumentPointeeAction(const A& value) : value_(value) {} - - template - void Perform(const ArgumentTuple& args) const { - CompileAssertTypesEqual(); - *::testing::get(args) = value_; +// whose N-th argument (0-based) is a pointer to x's type. +template +struct SetArgumentPointeeAction { + A value; + + template + void operator()(const Args&... args) const { + *::std::get(std::tie(args...)) = value; } - - private: - const A value_; - - GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; -template -class SetArgumentPointeeAction { - public: - // Constructs an action that sets the variable pointed to by the - // N-th function argument to 'proto'. Both ProtocolMessage and - // proto2::Message have the CopyFrom() method, so the same - // implementation works for both. - explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) { - proto_->CopyFrom(proto); - } - - template - void Perform(const ArgumentTuple& args) const { - CompileAssertTypesEqual(); - ::testing::get(args)->CopyFrom(*proto_); +// Implements the Invoke(object_ptr, &Class::Method) action. +template +struct InvokeMethodAction { + Class* const obj_ptr; + const MethodPtr method_ptr; + + template + auto operator()(Args&&... args) const + -> decltype((obj_ptr->*method_ptr)(std::forward(args)...)) { + return (obj_ptr->*method_ptr)(std::forward(args)...); } - - private: - const internal::linked_ptr proto_; - - GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; // Implements the InvokeWithoutArgs(f) action. The template argument // FunctionImpl is the implementation type of f, which can be either a // function pointer or a functor. InvokeWithoutArgs(f) can be used as an -// Action as long as f's type is compatible with F (i.e. f can be -// assigned to a tr1::function). +// Action as long as f's type is compatible with F. template -class InvokeWithoutArgsAction { - public: - // The c'tor makes a copy of function_impl (either a function - // pointer or a functor). - explicit InvokeWithoutArgsAction(FunctionImpl function_impl) - : function_impl_(function_impl) {} +struct InvokeWithoutArgsAction { + FunctionImpl function_impl; // Allows InvokeWithoutArgs(f) to be used as any action whose type is // compatible with f. - template - Result Perform(const ArgumentTuple&) { return function_impl_(); } - - private: - FunctionImpl function_impl_; - - GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction); + template + auto operator()(const Args&...) -> decltype(function_impl()) { + return function_impl(); + } }; // Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. template -class InvokeMethodWithoutArgsAction { - public: - InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr) - : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} +struct InvokeMethodWithoutArgsAction { + Class* const obj_ptr; + const MethodPtr method_ptr; - template - Result Perform(const ArgumentTuple&) const { - return (obj_ptr_->*method_ptr_)(); - } - - private: - Class* const obj_ptr_; - const MethodPtr method_ptr_; + using ReturnType = + decltype((std::declval()->*std::declval())()); - GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction); + template + ReturnType operator()(const Args&...) const { + return (obj_ptr->*method_ptr)(); + } }; // Implements the IgnoreResult(action) action. @@ -904,7 +1373,7 @@ class IgnoreResultAction { typedef typename internal::Function::Result Result; // Asserts at compile time that F returns void. - CompileAssertTypesEqual(); + static_assert(std::is_void::value, "Result type should be void."); return Action(new Impl(action_)); } @@ -918,7 +1387,7 @@ class IgnoreResultAction { explicit Impl(const A& action) : action_(action) {} - virtual void Perform(const ArgumentTuple& args) { + void Perform(const ArgumentTuple& args) override { // Performs the action and ignores its result. action_.Perform(args); } @@ -926,91 +1395,352 @@ class IgnoreResultAction { private: // Type OriginalFunction is the same as F except that its return // type is IgnoredValue. - typedef typename internal::Function::MakeResultIgnoredValue - OriginalFunction; + typedef + typename internal::Function::MakeResultIgnoredValue OriginalFunction; const Action action_; - - GTEST_DISALLOW_ASSIGN_(Impl); }; const A action_; +}; + +template +struct WithArgsAction { + InnerAction inner_action; + + // The signature of the function as seen by the inner action, given an out + // action with the given result and argument types. + template + using InnerSignature = + R(typename std::tuple_element>::type...); + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + template >::type...)>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + struct OA { + OnceAction> inner_action; + + R operator()(Args&&... args) && { + return std::move(inner_action) + .Call(std::get( + std::forward_as_tuple(std::forward(args)...))...); + } + }; + + return OA{std::move(inner_action)}; + } - GTEST_DISALLOW_ASSIGN_(IgnoreResultAction); + template >::type...)>>::value, + int>::type = 0> + operator Action() const { // NOLINT + Action> converted(inner_action); + + return [converted](Args&&... args) -> R { + return converted.Perform(std::forward_as_tuple( + std::get(std::forward_as_tuple(std::forward(args)...))...)); + }; + } }; -// A ReferenceWrapper object represents a reference to type T, -// which can be either const or not. It can be explicitly converted -// from, and implicitly converted to, a T&. Unlike a reference, -// ReferenceWrapper can be copied and can survive template type -// inference. This is used to support by-reference arguments in the -// InvokeArgument(...) action. The idea was from "reference -// wrappers" in tr1, which we don't have in our source tree yet. -template -class ReferenceWrapper { +template +class DoAllAction; + +// Base case: only a single action. +template +class DoAllAction { public: - // Constructs a ReferenceWrapper object from a T&. - explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& action) + : final_action_(std::forward(action)) {} + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + template >::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return std::move(final_action_); + } + + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>::value, + int>::type = 0> + operator Action() const { // NOLINT + return final_action_; + } - // Allows a ReferenceWrapper object to be implicitly converted to - // a T&. - operator T&() const { return *pointer_; } private: - T* pointer_; + FinalAction final_action_; }; -// Allows the expression ByRef(x) to be printed as a reference to x. -template -void PrintTo(const ReferenceWrapper& ref, ::std::ostream* os) { - T& value = ref; - UniversalPrinter::Print(value, os); -} +// Recursive case: support N actions by calling the initial action and then +// calling through to the base class containing N-1 actions. +template +class DoAllAction + : private DoAllAction { + private: + using Base = DoAllAction; + + // The type of reference that should be provided to an initial action for a + // mocked function parameter of type T. + // + // There are two quirks here: + // + // * Unlike most forwarding functions, we pass scalars through by value. + // This isn't strictly necessary because an lvalue reference would work + // fine too and be consistent with other non-reference types, but it's + // perhaps less surprising. + // + // For example if the mocked function has signature void(int), then it + // might seem surprising for the user's initial action to need to be + // convertible to Action. This is perhaps less + // surprising for a non-scalar type where there may be a performance + // impact, or it might even be impossible, to pass by value. + // + // * More surprisingly, `const T&` is often not a const reference type. + // By the reference collapsing rules in C++17 [dcl.ref]/6, if T refers to + // U& or U&& for some non-scalar type U, then InitialActionArgType is + // U&. In other words, we may hand over a non-const reference. + // + // So for example, given some non-scalar type Obj we have the following + // mappings: + // + // T InitialActionArgType + // ------- ----------------------- + // Obj const Obj& + // Obj& Obj& + // Obj&& Obj& + // const Obj const Obj& + // const Obj& const Obj& + // const Obj&& const Obj& + // + // In other words, the initial actions get a mutable view of an non-scalar + // argument if and only if the mock function itself accepts a non-const + // reference type. They are never given an rvalue reference to an + // non-scalar type. + // + // This situation makes sense if you imagine use with a matcher that is + // designed to write through a reference. For example, if the caller wants + // to fill in a reference argument and then return a canned value: + // + // EXPECT_CALL(mock, Call) + // .WillOnce(DoAll(SetArgReferee<0>(17), Return(19))); + // + template + using InitialActionArgType = + typename std::conditional::value, T, const T&>::type; -// Does two actions sequentially. Used for implementing the DoAll(a1, -// a2, ...) action. -template -class DoBothAction { public: - DoBothAction(Action1 action1, Action2 action2) - : action1_(action1), action2_(action2) {} + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& initial_action, + U&&... other_actions) + : Base({}, std::forward(other_actions)...), + initial_action_(std::forward(initial_action)) {} + + template ...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + OnceAction...)> initial_action; + OnceAction remaining_actions; + + R operator()(Args... args) && { + std::move(initial_action) + .Call(static_cast>(args)...); + + return std::move(remaining_actions).Call(std::forward(args)...); + } + }; + + return OA{ + std::move(initial_action_), + std::move(static_cast(*this)), + }; + } - // This template type conversion operator allows DoAll(a1, ..., a_n) - // to be used in ANY function of compatible type. - template - operator Action() const { - return Action(new Impl(action1_, action2_)); + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + // Both the initial action and the rest must support conversion to + // Action. + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator Action() const { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + Action...)> initial_action; + Action remaining_actions; + + R operator()(Args... args) const { + initial_action.Perform(std::forward_as_tuple( + static_cast>(args)...)); + + return remaining_actions.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{ + initial_action_, + static_cast(*this), + }; } private: - // Implements the DoAll(...) action for a particular function type F. - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - typedef typename Function::MakeResultVoid VoidResult; + InitialAction initial_action_; +}; - Impl(const Action& action1, const Action& action2) - : action1_(action1), action2_(action2) {} +template +struct ReturnNewAction { + T* operator()() const { + return internal::Apply( + [](const Params&... unpacked_params) { + return new T(unpacked_params...); + }, + params); + } + std::tuple params; +}; - virtual Result Perform(const ArgumentTuple& args) { - action1_.Perform(args); - return action2_.Perform(args); - } +template +struct ReturnArgAction { + template ::type> + auto operator()(Args&&... args) const -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { + return std::get(std::forward_as_tuple(std::forward(args)...)); + } +}; - private: - const Action action1_; - const Action action2_; +template +struct SaveArgAction { + Ptr pointer; - GTEST_DISALLOW_ASSIGN_(Impl); - }; + template + void operator()(const Args&... args) const { + *pointer = std::get(std::tie(args...)); + } +}; - Action1 action1_; - Action2 action2_; +template +struct SaveArgPointeeAction { + Ptr pointer; - GTEST_DISALLOW_ASSIGN_(DoBothAction); + template + void operator()(const Args&... args) const { + *pointer = *std::get(std::tie(args...)); + } +}; + +template +struct SetArgRefereeAction { + T value; + + template + void operator()(Args&&... args) const { + using argk_type = + typename ::std::tuple_element>::type; + static_assert(std::is_lvalue_reference::value, + "Argument must be a reference type."); + std::get(std::tie(args...)) = value; + } +}; + +template +struct SetArrayArgumentAction { + I1 first; + I2 last; + + template + void operator()(const Args&... args) const { + auto value = std::get(std::tie(args...)); + for (auto it = first; it != last; ++it, (void)++value) { + *value = *it; + } + } +}; + +template +struct DeleteArgAction { + template + void operator()(const Args&... args) const { + delete std::get(std::tie(args...)); + } +}; + +template +struct ReturnPointeeAction { + Ptr pointer; + template + auto operator()(const Args&...) const -> decltype(*pointer) { + return *pointer; + } }; +#if GTEST_HAS_EXCEPTIONS +template +struct ThrowAction { + T exception; + // We use a conversion operator to adapt to any return type. + template + operator Action() const { // NOLINT + T copy = exception; + return [copy](Args...) -> R { throw copy; }; + } +}; +#endif // GTEST_HAS_EXCEPTIONS + } // namespace internal // An Unused object can be implicitly constructed from ANY value. @@ -1029,9 +1759,9 @@ class DoBothAction { // return sqrt(x*x + y*y); // } // ... -// EXEPCT_CALL(mock, Foo("abc", _, _)) +// EXPECT_CALL(mock, Foo("abc", _, _)) // .WillOnce(Invoke(DistanceToOriginWithLabel)); -// EXEPCT_CALL(mock, Bar(5, _, _)) +// EXPECT_CALL(mock, Bar(5, _, _)) // .WillOnce(Invoke(DistanceToOriginWithIndex)); // // you could write @@ -1041,25 +1771,78 @@ class DoBothAction { // return sqrt(x*x + y*y); // } // ... -// EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); -// EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); typedef internal::IgnoredValue Unused; -// This constructor allows us to turn an Action object into an -// Action, as long as To's arguments can be implicitly converted -// to From's and From's return type cann be implicitly converted to -// To's. -template -template -Action::Action(const Action& from) - : impl_(new internal::ActionAdaptor(from)) {} - -// Creates an action that returns 'value'. 'value' is passed by value -// instead of const reference - otherwise Return("string literal") -// will trigger a compiler error about using array as initializer. +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. All but the last action will have a readonly view of the +// arguments. +template +internal::DoAllAction::type...> DoAll( + Action&&... action) { + return internal::DoAllAction::type...>( + {}, std::forward(action)...); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +internal::WithArgsAction::type, k> WithArg( + InnerAction&& action) { + return {std::forward(action)}; +} + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. +template +internal::WithArgsAction::type, k, ks...> +WithArgs(InnerAction&& action) { + return {std::forward(action)}; +} + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +internal::WithArgsAction::type> WithoutArgs( + InnerAction&& action) { + return {std::forward(action)}; +} + +// Creates an action that returns a value. +// +// The returned type can be used with a mock function returning a non-void, +// non-reference type U as follows: +// +// * If R is convertible to U and U is move-constructible, then the action can +// be used with WillOnce. +// +// * If const R& is convertible to U and U is copy-constructible, then the +// action can be used with both WillOnce and WillRepeatedly. +// +// The mock expectation contains the R value from which the U return value is +// constructed (a move/copy of the argument to Return). This means that the R +// value will survive at least until the mock object's expectations are cleared +// or the mock object is destroyed, meaning that U can safely be a +// reference-like type such as std::string_view: +// +// // The mock function returns a view of a copy of the string fed to +// // Return. The view is valid even after the action is performed. +// MockFunction mock; +// EXPECT_CALL(mock, Call).WillOnce(Return(std::string("taco"))); +// const std::string_view result = mock.AsStdFunction()(); +// EXPECT_EQ("taco", result); +// template internal::ReturnAction Return(R value) { - return internal::ReturnAction(internal::move(value)); + return internal::ReturnAction(std::move(value)); } // Creates an action that returns NULL. @@ -1078,6 +1861,10 @@ inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT return internal::ReturnRefAction(x); } +// Prevent using ReturnRef on reference to temporary. +template +internal::ReturnRefAction ReturnRef(R&&) = delete; + // Creates an action that returns the reference to a copy of the // argument. The copy is created when the action is constructed and // lives as long as the action. @@ -1086,13 +1873,32 @@ inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { return internal::ReturnRefOfCopyAction(x); } +// DEPRECATED: use Return(x) directly with WillOnce. +// // Modifies the parent action (a Return() action) to perform a move of the // argument instead of a copy. // Return(ByMove()) actions can only be executed once and will assert this // invariant. template internal::ByMoveWrapper ByMove(R x) { - return internal::ByMoveWrapper(internal::move(x)); + return internal::ByMoveWrapper(std::move(x)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin(std::vector vals) { + return internal::ReturnRoundRobinAction(std::move(vals)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin( + std::initializer_list vals) { + return internal::ReturnRoundRobinAction(std::vector(vals)); } // Creates an action that does the default action for the give mock function. @@ -1103,48 +1909,19 @@ inline internal::DoDefaultAction DoDefault() { // Creates an action that sets the variable pointed by the N-th // (0-based) function argument to 'value'. template -PolymorphicAction< - internal::SetArgumentPointeeAction< - N, T, internal::IsAProtocolMessage::value> > -SetArgPointee(const T& x) { - return MakePolymorphicAction(internal::SetArgumentPointeeAction< - N, T, internal::IsAProtocolMessage::value>(x)); +internal::SetArgumentPointeeAction SetArgPointee(T value) { + return {std::move(value)}; } -#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN) -// This overload allows SetArgPointee() to accept a string literal. -// GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish -// this overload from the templated version and emit a compile error. -template -PolymorphicAction< - internal::SetArgumentPointeeAction > -SetArgPointee(const char* p) { - return MakePolymorphicAction(internal::SetArgumentPointeeAction< - N, const char*, false>(p)); -} - -template -PolymorphicAction< - internal::SetArgumentPointeeAction > -SetArgPointee(const wchar_t* p) { - return MakePolymorphicAction(internal::SetArgumentPointeeAction< - N, const wchar_t*, false>(p)); -} -#endif - // The following version is DEPRECATED. template -PolymorphicAction< - internal::SetArgumentPointeeAction< - N, T, internal::IsAProtocolMessage::value> > -SetArgumentPointee(const T& x) { - return MakePolymorphicAction(internal::SetArgumentPointeeAction< - N, T, internal::IsAProtocolMessage::value>(x)); +internal::SetArgumentPointeeAction SetArgumentPointee(T value) { + return {std::move(value)}; } // Creates an action that sets a pointer referent to a given value. template -PolymorphicAction > Assign(T1* ptr, T2 val) { +PolymorphicAction> Assign(T1* ptr, T2 val) { return MakePolymorphicAction(internal::AssignAction(ptr, val)); } @@ -1152,32 +1929,46 @@ PolymorphicAction > Assign(T1* ptr, T2 val) { // Creates an action that sets errno and returns the appropriate error. template -PolymorphicAction > -SetErrnoAndReturn(int errval, T result) { +PolymorphicAction> SetErrnoAndReturn( + int errval, T result) { return MakePolymorphicAction( internal::SetErrnoAndReturnAction(errval, result)); } #endif // !GTEST_OS_WINDOWS_MOBILE -// Various overloads for InvokeWithoutArgs(). +// Various overloads for Invoke(). + +// Legacy function. +// Actions can now be implicitly constructed from callables. No need to create +// wrapper objects. +// This function exists for backwards compatibility. +template +typename std::decay::type Invoke(FunctionImpl&& function_impl) { + return std::forward(function_impl); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +internal::InvokeMethodAction Invoke(Class* obj_ptr, + MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; +} // Creates an action that invokes 'function_impl' with no argument. template -PolymorphicAction > +internal::InvokeWithoutArgsAction::type> InvokeWithoutArgs(FunctionImpl function_impl) { - return MakePolymorphicAction( - internal::InvokeWithoutArgsAction(function_impl)); + return {std::move(function_impl)}; } // Creates an action that invokes the given method on the given object // with no argument. template -PolymorphicAction > -InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) { - return MakePolymorphicAction( - internal::InvokeMethodWithoutArgsAction( - obj_ptr, method_ptr)); +internal::InvokeMethodWithoutArgsAction InvokeWithoutArgs( + Class* obj_ptr, MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; } // Creates an action that performs an_action and throws away its @@ -1195,11 +1986,313 @@ inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { // where Base is a base class of Derived, just write: // // ByRef(derived) +// +// N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper. +// However, it may still be used for consistency with ByMove(). template -inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT - return internal::ReferenceWrapper(l_value); +inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT + return ::std::reference_wrapper(l_value); } +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +template +internal::ReturnNewAction::type...> ReturnNew( + Params&&... params) { + return {std::forward_as_tuple(std::forward(params)...)}; +} + +// Action ReturnArg() returns the k-th argument of the mock function. +template +internal::ReturnArgAction ReturnArg() { + return {}; +} + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +internal::SaveArgAction SaveArg(Ptr pointer) { + return {pointer}; +} + +// Action SaveArgPointee(pointer) saves the value pointed to +// by the k-th (0-based) argument of the mock function to *pointer. +template +internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { + return {pointer}; +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +internal::SetArgRefereeAction::type> SetArgReferee( + T&& value) { + return {std::forward(value)}; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-th +// (0-based) argument, which can be either a pointer or an +// iterator. The action does not take ownership of the elements in the +// source range. +template +internal::SetArrayArgumentAction SetArrayArgument(I1 first, + I2 last) { + return {first, last}; +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +internal::DeleteArgAction DeleteArg() { + return {}; +} + +// This action returns the value pointed to by 'pointer'. +template +internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { + return {pointer}; +} + +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown. +#if GTEST_HAS_EXCEPTIONS +template +internal::ThrowAction::type> Throw(T&& exception) { + return {std::forward(exception)}; +} +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { + +// A macro from the ACTION* family (defined later in gmock-generated-actions.h) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// Builds an implementation of an Action<> for some particular signature, using +// a class defined by an ACTION* macro. +template +struct ActionImpl; + +template +struct ImplBase { + struct Holder { + // Allows each copy of the Action<> to get to the Impl. + explicit operator const Impl&() const { return *ptr; } + std::shared_ptr ptr; + }; + using type = typename std::conditional::value, + Impl, Holder>::type; +}; + +template +struct ActionImpl : ImplBase::type { + using Base = typename ImplBase::type; + using function_type = R(Args...); + using args_type = std::tuple; + + ActionImpl() = default; // Only defined if appropriate for Base. + explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} {} + + R operator()(Args&&... arg) const { + static constexpr size_t kMaxArgs = + sizeof...(Args) <= 10 ? sizeof...(Args) : 10; + return Apply(MakeIndexSequence{}, + MakeIndexSequence<10 - kMaxArgs>{}, + args_type{std::forward(arg)...}); + } + + template + R Apply(IndexSequence, IndexSequence, + const args_type& args) const { + // Impl need not be specific to the signature of action being implemented; + // only the implementing function body needs to have all of the specific + // types instantiated. Up to 10 of the args that are provided by the + // args_type get passed, followed by a dummy of unspecified type for the + // remainder up to 10 explicit args. + static constexpr ExcessiveArg kExcessArg{}; + return static_cast(*this) + .template gmock_PerformImpl< + /*function_type=*/function_type, /*return_type=*/R, + /*args_type=*/args_type, + /*argN_type=*/ + typename std::tuple_element::type...>( + /*args=*/args, std::get(args)..., + ((void)excess_id, kExcessArg)...); + } +}; + +// Stores a default-constructed Impl as part of the Action<>'s +// std::function<>. The Impl should be trivial to copy. +template +::testing::Action MakeAction() { + return ::testing::Action(ActionImpl()); +} + +// Stores just the one given instance of Impl. +template +::testing::Action MakeAction(std::shared_ptr impl) { + return ::testing::Action(ActionImpl(std::move(impl))); +} + +#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ + , const arg##i##_type& arg##i GTEST_ATTRIBUTE_UNUSED_ +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ + const args_type& args GTEST_ATTRIBUTE_UNUSED_ GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_ARG_UNUSED, , 10) + +#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \ + const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10) + +#define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type +#define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \ + GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10)) + +#define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type +#define GMOCK_ACTION_TYPENAME_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type +#define GMOCK_ACTION_TYPE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \ + , param##_type gmock_p##i +#define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \ + , std::forward(gmock_p##i) +#define GMOCK_ACTION_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \ + , param(::std::forward(gmock_p##i)) +#define GMOCK_ACTION_INIT_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params)) + +#define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param; +#define GMOCK_ACTION_FIELD_PARAMS_(params) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params) + +#define GMOCK_INTERNAL_ACTION(name, full_name, params) \ + template \ + class full_name { \ + public: \ + explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : impl_(std::make_shared( \ + GMOCK_ACTION_GVALUE_PARAMS_(params))) {} \ + full_name(const full_name&) = default; \ + full_name(full_name&&) noexcept = default; \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(impl_); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : GMOCK_ACTION_INIT_PARAMS_(params) {} \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + GMOCK_ACTION_FIELD_PARAMS_(params) \ + }; \ + std::shared_ptr impl_; \ + }; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) GTEST_MUST_USE_RESULT_; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ + return full_name( \ + GMOCK_ACTION_GVALUE_PARAMS_(params)); \ + } \ + template \ + template \ + return_type \ + full_name::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +} // namespace internal + +// Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored. +#define ACTION(name) \ + class name##Action { \ + public: \ + explicit name##Action() noexcept {} \ + name##Action(const name##Action&) noexcept {} \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + }; \ + }; \ + inline name##Action name() GTEST_MUST_USE_RESULT_; \ + inline name##Action name() { return name##Action(); } \ + template \ + return_type name##Action::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__)) + +#define ACTION_P2(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__)) + +#define ACTION_P3(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__)) + +#define ACTION_P4(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__)) + +#define ACTION_P5(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__)) + +#define ACTION_P6(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__)) + +#define ACTION_P7(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__)) + +#define ACTION_P8(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__)) + +#define ACTION_P9(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__)) + +#define ACTION_P10(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__)) + } // namespace testing -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-cardinalities.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-cardinalities.h index fc315f92a..b6ab648e5 100644 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-cardinalities.h +++ b/src/libtoast/gtest/googlemock/include/gmock/gmock-cardinalities.h @@ -26,8 +26,6 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (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 Mock - a framework for writing C++ mock classes. // @@ -35,14 +33,23 @@ // cardinalities can be defined by the user implementing the // CardinalityInterface interface if necessary. -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #include + +#include #include // NOLINT + #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // To implement a cardinality Foo, define: @@ -65,10 +72,12 @@ class CardinalityInterface { virtual int ConservativeLowerBound() const { return 0; } virtual int ConservativeUpperBound() const { return INT_MAX; } - // Returns true iff call_count calls will satisfy this cardinality. + // Returns true if and only if call_count calls will satisfy this + // cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - // Returns true iff call_count calls will saturate this cardinality. + // Returns true if and only if call_count calls will saturate this + // cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. @@ -77,9 +86,8 @@ class CardinalityInterface { // A Cardinality is a copyable and IMMUTABLE (except by assignment) // object that specifies how many times a mock function is expected to -// be called. The implementation of Cardinality is just a linked_ptr -// to const CardinalityInterface, so copying is fairly cheap. -// Don't inherit from Cardinality! +// be called. The implementation of Cardinality is just a std::shared_ptr +// to const CardinalityInterface. Don't inherit from Cardinality! class GTEST_API_ Cardinality { public: // Constructs a null cardinality. Needed for storing Cardinality @@ -94,21 +102,23 @@ class GTEST_API_ Cardinality { int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } - // Returns true iff call_count calls will satisfy this cardinality. + // Returns true if and only if call_count calls will satisfy this + // cardinality. bool IsSatisfiedByCallCount(int call_count) const { return impl_->IsSatisfiedByCallCount(call_count); } - // Returns true iff call_count calls will saturate this cardinality. + // Returns true if and only if call_count calls will saturate this + // cardinality. bool IsSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count); } - // Returns true iff call_count calls will over-saturate this + // Returns true if and only if call_count calls will over-saturate this // cardinality, i.e. exceed the maximum number of allowed calls. bool IsOverSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count) && - !impl_->IsSatisfiedByCallCount(call_count); + !impl_->IsSatisfiedByCallCount(call_count); } // Describes self to an ostream @@ -119,7 +129,7 @@ class GTEST_API_ Cardinality { ::std::ostream* os); private: - internal::linked_ptr impl_; + std::shared_ptr impl_; }; // Creates a cardinality that allows at least n calls. @@ -144,4 +154,6 @@ inline Cardinality MakeCardinality(const CardinalityInterface* c) { } // namespace testing -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-function-mocker.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-function-mocker.h new file mode 100644 index 000000000..f565d980c --- /dev/null +++ b/src/libtoast/gtest/googlemock/include/gmock/gmock-function-mocker.h @@ -0,0 +1,514 @@ +// 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. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements MOCK_METHOD. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT +#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT + +#include // IWYU pragma: keep +#include // IWYU pragma: keep + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-pp.h" + +namespace testing { +namespace internal { +template +using identity_t = T; + +template +struct ThisRefAdjuster { + template + using AdjustT = typename std::conditional< + std::is_const::type>::value, + typename std::conditional::value, + const T&, const T&&>::type, + typename std::conditional::value, T&, + T&&>::type>::type; + + template + static AdjustT Adjust(const MockType& mock) { + return static_cast>(const_cast(mock)); + } +}; + +constexpr bool PrefixOf(const char* a, const char* b) { + return *a == 0 || (*a == *b && internal::PrefixOf(a + 1, b + 1)); +} + +template +constexpr bool StartsWith(const char (&prefix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(prefix, str); +} + +template +constexpr bool EndsWith(const char (&suffix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(suffix, str + M - N); +} + +template +constexpr bool Equals(const char (&a)[N], const char (&b)[M]) { + return N == M && internal::PrefixOf(a, b); +} + +template +constexpr bool ValidateSpec(const char (&spec)[N]) { + return internal::Equals("const", spec) || + internal::Equals("override", spec) || + internal::Equals("final", spec) || + internal::Equals("noexcept", spec) || + (internal::StartsWith("noexcept(", spec) && + internal::EndsWith(")", spec)) || + internal::Equals("ref(&)", spec) || + internal::Equals("ref(&&)", spec) || + (internal::StartsWith("Calltype(", spec) && + internal::EndsWith(")", spec)); +} + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; +} // namespace testing + +#define MOCK_METHOD(...) \ + GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \ + GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ()) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \ + GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \ + GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \ + GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \ + (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args))) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_WRONG_ARITY(...) \ + static_assert( \ + false, \ + "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \ + "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \ + "enclosed in parentheses. If _Ret is a type with unprotected commas, " \ + "it must also be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \ + static_assert( \ + GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \ + GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \ + static_assert( \ + std::is_function<__VA_ARGS__>::value, \ + "Signature must be a function type, maybe return type contains " \ + "unprotected comma."); \ + static_assert( \ + ::testing::tuple_size::ArgumentTuple>::value == _N, \ + "This method does not take " GMOCK_PP_STRINGIZE( \ + _N) " arguments. Parenthesize all types with unprotected commas.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) + +#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \ + _Override, _Final, _NoexceptSpec, \ + _CallType, _RefSpec, _Signature) \ + typename ::testing::internal::Function::Result \ + GMOCK_INTERNAL_EXPAND(_CallType) \ + _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) _RefSpec _NoexceptSpec \ + GMOCK_PP_IF(_Override, override, ) GMOCK_PP_IF(_Final, final, ) { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .SetOwnerAndName(this, #_MethodName); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) _RefSpec { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + const ::testing::internal::WithoutMatchers&, \ + GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \ + GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \ + return ::testing::internal::ThisRefAdjuster::Adjust(*this) \ + .gmock_##_MethodName(GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \ + } \ + mutable ::testing::FunctionMocker \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) + +#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__ + +// Valid modifiers. +#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \ + GMOCK_PP_HAS_COMMA( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple)) + +#define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple) + +#define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \ + _elem, ) + +#define GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE, ~, _Tuple) + +#define GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple) + +#define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem) \ + GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#ifdef GMOCK_INTERNAL_STRICT_SPEC_ASSERT +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + ::testing::internal::ValidateSpec(GMOCK_PP_STRINGIZE(_elem)), \ + "Token \'" GMOCK_PP_STRINGIZE( \ + _elem) "\' cannot be recognized as a valid specification " \ + "modifier. Is a ',' missing?"); +#else +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem))) == 1, \ + GMOCK_PP_STRINGIZE( \ + _elem) " cannot be recognized as a valid specification modifier."); +#endif // GMOCK_INTERNAL_STRICT_SPEC_ASSERT + +// Modifiers implementation. +#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CONST_I_const , + +#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override , + +#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_FINAL_I_final , + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept , + +#define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_REF_I_ref , + +#define GMOCK_INTERNAL_UNPACK_ref(x) x + +#define GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CALLTYPE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CALLTYPE_I_Calltype , + +#define GMOCK_INTERNAL_UNPACK_Calltype(...) __VA_ARGS__ + +// Note: The use of `identity_t` here allows _Ret to represent return types that +// would normally need to be specified in a different way. For example, a method +// returning a function pointer must be written as +// +// fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...) +// +// But we only support placing the return type at the beginning. To handle this, +// we wrap all calls in identity_t, so that a declaration will be expanded to +// +// identity_t method(method_args_t...) +// +// This allows us to work around the syntactic oddities of function/method +// types. +#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \ + ::testing::internal::identity_t( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args)) + +#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \ + GMOCK_PP_IDENTITY) \ + (_elem) + +#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::std::forward(gmock_a##_i) + +#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \ + GMOCK_PP_COMMA_IF(_i) \ + gmock_a##_i + +#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::testing::A() + +#define GMOCK_INTERNAL_ARG_O(_i, ...) \ + typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type + +#define GMOCK_INTERNAL_MATCHER_O(_i, ...) \ + const ::testing::Matcher::template Arg<_i>::type>& + +#define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__) +#define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__) +#define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__) +#define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__) +#define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__) +#define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__) +#define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__) +#define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__) +#define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__) +#define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__) +#define MOCK_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__) +#define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__) +#define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__) +#define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__) +#define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__) +#define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__) +#define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__) +#define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__) +#define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__) +#define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__) +#define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + args_num, ::testing::internal::identity_t<__VA_ARGS__>); \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, , \ + (::testing::internal::identity_t<__VA_ARGS__>)) + +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h deleted file mode 100644 index b5a889c0c..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h +++ /dev/null @@ -1,2377 +0,0 @@ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! - -// 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 Mock - a framework for writing C++ mock classes. -// -// This file implements some commonly used variadic actions. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ - -#include "gmock/gmock-actions.h" -#include "gmock/internal/gmock-port.h" - -namespace testing { -namespace internal { - -// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary -// function or method with the unpacked values, where F is a function -// type that takes N arguments. -template -class InvokeHelper; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple<>&) { - return function(); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple<>&) { - return (obj_ptr->*method_ptr)(); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args), get<5>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), get<5>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args), get<5>(args), get<6>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), get<5>(args), - get<6>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args), get<5>(args), get<6>(args), - get<7>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), get<5>(args), - get<6>(args), get<7>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args), get<5>(args), get<6>(args), - get<7>(args), get<8>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), get<5>(args), - get<6>(args), get<7>(args), get<8>(args)); - } -}; - -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple& args) { - return function(get<0>(args), get<1>(args), get<2>(args), - get<3>(args), get<4>(args), get<5>(args), get<6>(args), - get<7>(args), get<8>(args), get<9>(args)); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple& args) { - return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), - get<2>(args), get<3>(args), get<4>(args), get<5>(args), - get<6>(args), get<7>(args), get<8>(args), get<9>(args)); - } -}; - -// An INTERNAL macro for extracting the type of a tuple field. It's -// subject to change without notice - DO NOT USE IN USER CODE! -#define GMOCK_FIELD_(Tuple, N) \ - typename ::testing::tuple_element::type - -// SelectArgs::type is the -// type of an n-ary function whose i-th (1-based) argument type is the -// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple -// type, and whose return type is Result. For example, -// SelectArgs, 0, 3>::type -// is int(bool, long). -// -// SelectArgs::Select(args) -// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. -// For example, -// SelectArgs, 2, 0>::Select( -// ::testing::make_tuple(true, 'a', 2.5)) -// returns tuple (2.5, true). -// -// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be -// in the range [0, 10]. Duplicates are allowed and they don't have -// to be in an ascending or descending order. - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), - GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), - GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9), - GMOCK_FIELD_(ArgumentTuple, k10)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args), get(args), get(args), - get(args), get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& /* args */) { - return SelectedArgs(); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), - GMOCK_FIELD_(ArgumentTuple, k6)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), - GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args), get(args), get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), - GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), - GMOCK_FIELD_(ArgumentTuple, k8)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args), get(args), get(args), - get(args)); - } -}; - -template -class SelectArgs { - public: - typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), - GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), - GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), - GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), - GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9)); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs(get(args), get(args), get(args), - get(args), get(args), get(args), get(args), - get(args), get(args)); - } -}; - -#undef GMOCK_FIELD_ - -// Implements the WithArgs action. -template -class WithArgsAction { - public: - explicit WithArgsAction(const InnerAction& action) : action_(action) {} - - template - operator Action() const { return MakeAction(new Impl(action_)); } - - private: - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - explicit Impl(const InnerAction& action) : action_(action) {} - - virtual Result Perform(const ArgumentTuple& args) { - return action_.Perform(SelectArgs::Select(args)); - } - - private: - typedef typename SelectArgs::type InnerFunctionType; - - Action action_; - }; - - const InnerAction action_; - - GTEST_DISALLOW_ASSIGN_(WithArgsAction); -}; - -// A macro from the ACTION* family (defined later in this file) -// defines an action that can be used in a mock function. Typically, -// these actions only care about a subset of the arguments of the mock -// function. For example, if such an action only uses the second -// argument, it can be used in any mock function that takes >= 2 -// arguments where the type of the second argument is compatible. -// -// Therefore, the action implementation must be prepared to take more -// arguments than it needs. The ExcessiveArg type is used to -// represent those excessive arguments. In order to keep the compiler -// error messages tractable, we define it in the testing namespace -// instead of testing::internal. However, this is an INTERNAL TYPE -// and subject to change without notice, so a user MUST NOT USE THIS -// TYPE DIRECTLY. -struct ExcessiveArg {}; - -// A helper class needed for implementing the ACTION* macros. -template -class ActionHelper { - public: - static Result Perform(Impl* impl, const ::testing::tuple<>& args) { - return impl->template gmock_PerformImpl<>(args, ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), - get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), - get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), - get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, - get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), - ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, - get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), - get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, - get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), - get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), - get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), - get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), - ExcessiveArg()); - } - - template - static Result Perform(Impl* impl, const ::testing::tuple& args) { - return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), - get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), - get<9>(args)); - } -}; - -} // namespace internal - -// Various overloads for Invoke(). - -// WithArgs(an_action) creates an action that passes -// the selected arguments of the mock function to an_action and -// performs it. It serves as an adaptor between actions with -// different argument lists. C++ doesn't support default arguments for -// function templates, so we have to overload it. -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -template -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - -// Creates an action that does actions a1, a2, ..., sequentially in -// each invocation. -template -inline internal::DoBothAction -DoAll(Action1 a1, Action2 a2) { - return internal::DoBothAction(a1, a2); -} - -template -inline internal::DoBothAction > -DoAll(Action1 a1, Action2 a2, Action3 a3) { - return DoAll(a1, DoAll(a2, a3)); -} - -template -inline internal::DoBothAction > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) { - return DoAll(a1, DoAll(a2, a3, a4)); -} - -template -inline internal::DoBothAction > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) { - return DoAll(a1, DoAll(a2, a3, a4, a5)); -} - -template -inline internal::DoBothAction > > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) { - return DoAll(a1, DoAll(a2, a3, a4, a5, a6)); -} - -template -inline internal::DoBothAction > > > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, - Action7 a7) { - return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7)); -} - -template -inline internal::DoBothAction > > > > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, - Action7 a7, Action8 a8) { - return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8)); -} - -template -inline internal::DoBothAction > > > > > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, - Action7 a7, Action8 a8, Action9 a9) { - return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9)); -} - -template -inline internal::DoBothAction > > > > > > > > -DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, - Action7 a7, Action8 a8, Action9 a9, Action10 a10) { - return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10)); -} - -} // namespace testing - -// The ACTION* family of macros can be used in a namespace scope to -// define custom actions easily. The syntax: -// -// ACTION(name) { statements; } -// -// will define an action with the given name that executes the -// statements. The value returned by the statements will be used as -// the return value of the action. Inside the statements, you can -// refer to the K-th (0-based) argument of the mock function by -// 'argK', and refer to its type by 'argK_type'. For example: -// -// ACTION(IncrementArg1) { -// arg1_type temp = arg1; -// return ++(*temp); -// } -// -// allows you to write -// -// ...WillOnce(IncrementArg1()); -// -// You can also refer to the entire argument tuple and its type by -// 'args' and 'args_type', and refer to the mock function type and its -// return type by 'function_type' and 'return_type'. -// -// Note that you don't need to specify the types of the mock function -// arguments. However rest assured that your code is still type-safe: -// you'll get a compiler error if *arg1 doesn't support the ++ -// operator, or if the type of ++(*arg1) isn't compatible with the -// mock function's return type, for example. -// -// Sometimes you'll want to parameterize the action. For that you can use -// another macro: -// -// ACTION_P(name, param_name) { statements; } -// -// For example: -// -// ACTION_P(Add, n) { return arg0 + n; } -// -// will allow you to write: -// -// ...WillOnce(Add(5)); -// -// Note that you don't need to provide the type of the parameter -// either. If you need to reference the type of a parameter named -// 'foo', you can write 'foo_type'. For example, in the body of -// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type -// of 'n'. -// -// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support -// multi-parameter actions. -// -// For the purpose of typing, you can view -// -// ACTION_Pk(Foo, p1, ..., pk) { ... } -// -// as shorthand for -// -// template -// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } -// -// In particular, you can provide the template type arguments -// explicitly when invoking Foo(), as in Foo(5, false); -// although usually you can rely on the compiler to infer the types -// for you automatically. You can assign the result of expression -// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. -// -// You can also overload actions with different numbers of parameters: -// -// ACTION_P(Plus, a) { ... } -// ACTION_P2(Plus, a, b) { ... } -// -// While it's tempting to always use the ACTION* macros when defining -// a new action, you should also consider implementing ActionInterface -// or using MakePolymorphicAction() instead, especially if you need to -// use the action a lot. While these approaches require more work, -// they give you more control on the types of the mock function -// arguments and the action parameters, which in general leads to -// better compiler error messages that pay off in the long run. They -// also allow overloading actions based on parameter types (as opposed -// to just based on the number of parameters). -// -// CAVEAT: -// -// ACTION*() can only be used in a namespace scope. The reason is -// that C++ doesn't yet allow function-local types to be used to -// instantiate templates. The up-coming C++0x standard will fix this. -// Once that's done, we'll consider supporting using ACTION*() inside -// a function. -// -// MORE INFORMATION: -// -// To learn more about using these macros, please search for 'ACTION' -// on http://code.google.com/p/googlemock/wiki/CookBook. - -// An internal macro needed for implementing ACTION*(). -#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ - const args_type& args GTEST_ATTRIBUTE_UNUSED_, \ - arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \ - arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \ - arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \ - arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \ - arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \ - arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \ - arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \ - arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \ - arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \ - arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_ - -// Sometimes you want to give an action explicit template parameters -// that cannot be inferred from its value parameters. ACTION() and -// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that -// and can be viewed as an extension to ACTION() and ACTION_P*(). -// -// The syntax: -// -// ACTION_TEMPLATE(ActionName, -// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), -// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -// -// defines an action template that takes m explicit template -// parameters and n value parameters. name_i is the name of the i-th -// template parameter, and kind_i specifies whether it's a typename, -// an integral constant, or a template. p_i is the name of the i-th -// value parameter. -// -// Example: -// -// // DuplicateArg(output) converts the k-th argument of the mock -// // function to type T and copies it to *output. -// ACTION_TEMPLATE(DuplicateArg, -// HAS_2_TEMPLATE_PARAMS(int, k, typename, T), -// AND_1_VALUE_PARAMS(output)) { -// *output = T(::testing::get(args)); -// } -// ... -// int n; -// EXPECT_CALL(mock, Foo(_, _)) -// .WillOnce(DuplicateArg<1, unsigned char>(&n)); -// -// To create an instance of an action template, write: -// -// ActionName(v1, ..., v_n) -// -// where the ts are the template arguments and the vs are the value -// arguments. The value argument types are inferred by the compiler. -// If you want to explicitly specify the value argument types, you can -// provide additional template arguments: -// -// ActionName(v1, ..., v_n) -// -// where u_i is the desired type of v_i. -// -// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the -// number of value parameters, but not on the number of template -// parameters. Without the restriction, the meaning of the following -// is unclear: -// -// OverloadedAction(x); -// -// Are we using a single-template-parameter action where 'bool' refers -// to the type of x, or are we using a two-template-parameter action -// where the compiler is asked to infer the type of x? -// -// Implementation notes: -// -// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and -// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for -// implementing ACTION_TEMPLATE. The main trick we use is to create -// new macro invocations when expanding a macro. For example, we have -// -// #define ACTION_TEMPLATE(name, template_params, value_params) -// ... GMOCK_INTERNAL_DECL_##template_params ... -// -// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) -// to expand to -// -// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... -// -// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the -// preprocessor will continue to expand it to -// -// ... typename T ... -// -// This technique conforms to the C++ standard and is portable. It -// allows us to implement action templates using O(N) code, where N is -// the maximum number of template/value parameters supported. Without -// using it, we'd have to devote O(N^2) amount of code to implement all -// combinations of m and n. - -// Declares the template parameters. -#define GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(kind0, name0) kind0 name0 -#define GMOCK_INTERNAL_DECL_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ - name1) kind0 name0, kind1 name1 -#define GMOCK_INTERNAL_DECL_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2) kind0 name0, kind1 name1, kind2 name2 -#define GMOCK_INTERNAL_DECL_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3) kind0 name0, kind1 name1, kind2 name2, \ - kind3 name3 -#define GMOCK_INTERNAL_DECL_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4) kind0 name0, kind1 name1, \ - kind2 name2, kind3 name3, kind4 name4 -#define GMOCK_INTERNAL_DECL_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5) kind0 name0, \ - kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5 -#define GMOCK_INTERNAL_DECL_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ - name6) kind0 name0, kind1 name1, kind2 name2, kind3 name3, kind4 name4, \ - kind5 name5, kind6 name6 -#define GMOCK_INTERNAL_DECL_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ - kind7, name7) kind0 name0, kind1 name1, kind2 name2, kind3 name3, \ - kind4 name4, kind5 name5, kind6 name6, kind7 name7 -#define GMOCK_INTERNAL_DECL_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ - kind7, name7, kind8, name8) kind0 name0, kind1 name1, kind2 name2, \ - kind3 name3, kind4 name4, kind5 name5, kind6 name6, kind7 name7, \ - kind8 name8 -#define GMOCK_INTERNAL_DECL_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ - name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ - name6, kind7, name7, kind8, name8, kind9, name9) kind0 name0, \ - kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5, \ - kind6 name6, kind7 name7, kind8 name8, kind9 name9 - -// Lists the template parameters. -#define GMOCK_INTERNAL_LIST_HAS_1_TEMPLATE_PARAMS(kind0, name0) name0 -#define GMOCK_INTERNAL_LIST_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ - name1) name0, name1 -#define GMOCK_INTERNAL_LIST_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2) name0, name1, name2 -#define GMOCK_INTERNAL_LIST_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3) name0, name1, name2, name3 -#define GMOCK_INTERNAL_LIST_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4) name0, name1, name2, name3, \ - name4 -#define GMOCK_INTERNAL_LIST_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5) name0, name1, \ - name2, name3, name4, name5 -#define GMOCK_INTERNAL_LIST_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ - name6) name0, name1, name2, name3, name4, name5, name6 -#define GMOCK_INTERNAL_LIST_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ - kind7, name7) name0, name1, name2, name3, name4, name5, name6, name7 -#define GMOCK_INTERNAL_LIST_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ - kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ - kind7, name7, kind8, name8) name0, name1, name2, name3, name4, name5, \ - name6, name7, name8 -#define GMOCK_INTERNAL_LIST_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ - name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ - name6, kind7, name7, kind8, name8, kind9, name9) name0, name1, name2, \ - name3, name4, name5, name6, name7, name8, name9 - -// Declares the types of value parameters. -#define GMOCK_INTERNAL_DECL_TYPE_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_DECL_TYPE_AND_1_VALUE_PARAMS(p0) , typename p0##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_2_VALUE_PARAMS(p0, p1) , \ - typename p0##_type, typename p1##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , \ - typename p0##_type, typename p1##_type, typename p2##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ - typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ - typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type, typename p4##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ - typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type, typename p4##_type, typename p5##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6) , typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type, typename p4##_type, typename p5##_type, \ - typename p6##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7) , typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type, typename p4##_type, typename p5##_type, \ - typename p6##_type, typename p7##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8) , typename p0##_type, typename p1##_type, typename p2##_type, \ - typename p3##_type, typename p4##_type, typename p5##_type, \ - typename p6##_type, typename p7##_type, typename p8##_type -#define GMOCK_INTERNAL_DECL_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8, p9) , typename p0##_type, typename p1##_type, \ - typename p2##_type, typename p3##_type, typename p4##_type, \ - typename p5##_type, typename p6##_type, typename p7##_type, \ - typename p8##_type, typename p9##_type - -// Initializes the value parameters. -#define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\ - () -#define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\ - (p0##_type gmock_p0) : p0(gmock_p0) -#define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\ - (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1) -#define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\ - (p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) -#define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3) -#define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) -#define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) -#define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) -#define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7) -#define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8) -#define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8, p9)\ - (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ - p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8), p9(gmock_p9) - -// Declares the fields for storing the value parameters. -#define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0; -#define GMOCK_INTERNAL_DEFN_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0; \ - p1##_type p1; -#define GMOCK_INTERNAL_DEFN_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0; \ - p1##_type p1; p2##_type p2; -#define GMOCK_INTERNAL_DEFN_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0; \ - p1##_type p1; p2##_type p2; p3##_type p3; -#define GMOCK_INTERNAL_DEFN_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ - p4) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; -#define GMOCK_INTERNAL_DEFN_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ - p5) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ - p5##_type p5; -#define GMOCK_INTERNAL_DEFN_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ - p5##_type p5; p6##_type p6; -#define GMOCK_INTERNAL_DEFN_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ - p5##_type p5; p6##_type p6; p7##_type p7; -#define GMOCK_INTERNAL_DEFN_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ - p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; -#define GMOCK_INTERNAL_DEFN_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8, p9) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ - p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; \ - p9##_type p9; - -// Lists the value parameters. -#define GMOCK_INTERNAL_LIST_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_LIST_AND_1_VALUE_PARAMS(p0) p0 -#define GMOCK_INTERNAL_LIST_AND_2_VALUE_PARAMS(p0, p1) p0, p1 -#define GMOCK_INTERNAL_LIST_AND_3_VALUE_PARAMS(p0, p1, p2) p0, p1, p2 -#define GMOCK_INTERNAL_LIST_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0, p1, p2, p3 -#define GMOCK_INTERNAL_LIST_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) p0, p1, \ - p2, p3, p4 -#define GMOCK_INTERNAL_LIST_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) p0, \ - p1, p2, p3, p4, p5 -#define GMOCK_INTERNAL_LIST_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6) p0, p1, p2, p3, p4, p5, p6 -#define GMOCK_INTERNAL_LIST_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7) p0, p1, p2, p3, p4, p5, p6, p7 -#define GMOCK_INTERNAL_LIST_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8) p0, p1, p2, p3, p4, p5, p6, p7, p8 -#define GMOCK_INTERNAL_LIST_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8, p9) p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 - -// Lists the value parameter types. -#define GMOCK_INTERNAL_LIST_TYPE_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_LIST_TYPE_AND_1_VALUE_PARAMS(p0) , p0##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_2_VALUE_PARAMS(p0, p1) , p0##_type, \ - p1##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , p0##_type, \ - p1##_type, p2##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ - p0##_type, p1##_type, p2##_type, p3##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ - p0##_type, p1##_type, p2##_type, p3##_type, p4##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ - p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, \ - p6##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ - p5##_type, p6##_type, p7##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ - p5##_type, p6##_type, p7##_type, p8##_type -#define GMOCK_INTERNAL_LIST_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8, p9) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ - p5##_type, p6##_type, p7##_type, p8##_type, p9##_type - -// Declares the value parameters. -#define GMOCK_INTERNAL_DECL_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_DECL_AND_1_VALUE_PARAMS(p0) p0##_type p0 -#define GMOCK_INTERNAL_DECL_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0, \ - p1##_type p1 -#define GMOCK_INTERNAL_DECL_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0, \ - p1##_type p1, p2##_type p2 -#define GMOCK_INTERNAL_DECL_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0, \ - p1##_type p1, p2##_type p2, p3##_type p3 -#define GMOCK_INTERNAL_DECL_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ - p4) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4 -#define GMOCK_INTERNAL_DECL_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ - p5) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ - p5##_type p5 -#define GMOCK_INTERNAL_DECL_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ - p6) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ - p5##_type p5, p6##_type p6 -#define GMOCK_INTERNAL_DECL_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ - p5##_type p5, p6##_type p6, p7##_type p7 -#define GMOCK_INTERNAL_DECL_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8 -#define GMOCK_INTERNAL_DECL_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8, p9) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ - p9##_type p9 - -// The suffix of the class template implementing the action template. -#define GMOCK_INTERNAL_COUNT_AND_0_VALUE_PARAMS() -#define GMOCK_INTERNAL_COUNT_AND_1_VALUE_PARAMS(p0) P -#define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2 -#define GMOCK_INTERNAL_COUNT_AND_3_VALUE_PARAMS(p0, p1, p2) P3 -#define GMOCK_INTERNAL_COUNT_AND_4_VALUE_PARAMS(p0, p1, p2, p3) P4 -#define GMOCK_INTERNAL_COUNT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) P5 -#define GMOCK_INTERNAL_COUNT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) P6 -#define GMOCK_INTERNAL_COUNT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6) P7 -#define GMOCK_INTERNAL_COUNT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7) P8 -#define GMOCK_INTERNAL_COUNT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8) P9 -#define GMOCK_INTERNAL_COUNT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ - p7, p8, p9) P10 - -// The name of the class template implementing the action template. -#define GMOCK_ACTION_CLASS_(name, value_params)\ - GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) - -#define ACTION_TEMPLATE(name, template_params, value_params)\ - template \ - class GMOCK_ACTION_CLASS_(name, value_params) {\ - public:\ - explicit GMOCK_ACTION_CLASS_(name, value_params)\ - GMOCK_INTERNAL_INIT_##value_params {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - GMOCK_INTERNAL_DEFN_##value_params\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(\ - new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ - }\ - GMOCK_INTERNAL_DEFN_##value_params\ - private:\ - GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ - };\ - template \ - inline GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ - GMOCK_INTERNAL_DECL_##value_params) {\ - return GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ - GMOCK_INTERNAL_LIST_##value_params);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ - gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION(name)\ - class name##Action {\ - public:\ - name##Action() {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl() {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl());\ - }\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##Action);\ - };\ - inline name##Action name() {\ - return name##Action();\ - }\ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##Action::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P(name, p0)\ - template \ - class name##ActionP {\ - public:\ - explicit name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0));\ - }\ - p0##_type p0;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP);\ - };\ - template \ - inline name##ActionP name(p0##_type p0) {\ - return name##ActionP(p0);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P2(name, p0, p1)\ - template \ - class name##ActionP2 {\ - public:\ - name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ - p1(gmock_p1) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ - p1(gmock_p1) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP2);\ - };\ - template \ - inline name##ActionP2 name(p0##_type p0, \ - p1##_type p1) {\ - return name##ActionP2(p0, p1);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP2::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P3(name, p0, p1, p2)\ - template \ - class name##ActionP3 {\ - public:\ - name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP3);\ - };\ - template \ - inline name##ActionP3 name(p0##_type p0, \ - p1##_type p1, p2##_type p2) {\ - return name##ActionP3(p0, p1, p2);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP3::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P4(name, p0, p1, p2, p3)\ - template \ - class name##ActionP4 {\ - public:\ - name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP4);\ - };\ - template \ - inline name##ActionP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ - p3##_type p3) {\ - return name##ActionP4(p0, p1, \ - p2, p3);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP4::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P5(name, p0, p1, p2, p3, p4)\ - template \ - class name##ActionP5 {\ - public:\ - name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, \ - p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \ - p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP5);\ - };\ - template \ - inline name##ActionP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4) {\ - return name##ActionP5(p0, p1, p2, p3, p4);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP5::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\ - template \ - class name##ActionP6 {\ - public:\ - name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP6);\ - };\ - template \ - inline name##ActionP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ - p3##_type p3, p4##_type p4, p5##_type p5) {\ - return name##ActionP6(p0, p1, p2, p3, p4, p5);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP6::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\ - template \ - class name##ActionP7 {\ - public:\ - name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ - p6(gmock_p6) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ - p6));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP7);\ - };\ - template \ - inline name##ActionP7 name(p0##_type p0, p1##_type p1, \ - p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ - p6##_type p6) {\ - return name##ActionP7(p0, p1, p2, p3, p4, p5, p6);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP7::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\ - template \ - class name##ActionP8 {\ - public:\ - name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, \ - p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \ - p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \ - p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ - p6, p7));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP8);\ - };\ - template \ - inline name##ActionP8 name(p0##_type p0, \ - p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ - p6##_type p6, p7##_type p7) {\ - return name##ActionP8(p0, p1, p2, p3, p4, p5, \ - p6, p7);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP8::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\ - template \ - class name##ActionP9 {\ - public:\ - name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7), p8(gmock_p8) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP9);\ - };\ - template \ - inline name##ActionP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ - p8##_type p8) {\ - return name##ActionP9(p0, p1, p2, \ - p3, p4, p5, p6, p7, p8);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP9::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\ - template \ - class name##ActionP10 {\ - public:\ - name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ - p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template \ - return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ - arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ - arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ - arg9_type arg9) const;\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - p9##_type p9;\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ - p6, p7, p8, p9));\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - p9##_type p9;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##ActionP10);\ - };\ - template \ - inline name##ActionP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ - p9##_type p9) {\ - return name##ActionP10(p0, \ - p1, p2, p3, p4, p5, p6, p7, p8, p9);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - name##ActionP10::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -namespace testing { - - -// The ACTION*() macros trigger warning C4100 (unreferenced formal -// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in -// the macro definition, as the warnings are generated when the macro -// is expanded and macro expansion cannot contain #pragma. Therefore -// we suppress them here. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4100) -#endif - -// Various overloads for InvokeArgument(). -// -// The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th -// (0-based) argument, which must be a k-ary callable, of the mock -// function, with arguments a1, a2, ..., a_k. -// -// Notes: -// -// 1. The arguments are passed by value by default. If you need to -// pass an argument by reference, wrap it inside ByRef(). For -// example, -// -// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) -// -// passes 5 and string("Hello") by value, and passes foo by -// reference. -// -// 2. If the callable takes an argument by reference but ByRef() is -// not used, it will receive the reference to a copy of the value, -// instead of the original value. For example, when the 0-th -// argument of the mock function takes a const string&, the action -// -// InvokeArgument<0>(string("Hello")) -// -// makes a copy of the temporary string("Hello") object and passes a -// reference of the copy, instead of the original temporary object, -// to the callable. This makes it easy for a user to define an -// InvokeArgument action from temporary values and have it performed -// later. - -namespace internal { -namespace invoke_argument { - -// Appears in InvokeArgumentAdl's argument list to help avoid -// accidental calls to user functions of the same name. -struct AdlTag {}; - -// InvokeArgumentAdl - a helper for InvokeArgument. -// The basic overloads are provided here for generic functors. -// Overloads for other custom-callables are provided in the -// internal/custom/callback-actions.h header. - -template -R InvokeArgumentAdl(AdlTag, F f) { - return f(); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1) { - return f(a1); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2) { - return f(a1, a2); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3) { - return f(a1, a2, a3); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4) { - return f(a1, a2, a3, a4); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - return f(a1, a2, a3, a4, a5); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { - return f(a1, a2, a3, a4, a5, a6); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, - A7 a7) { - return f(a1, a2, a3, a4, a5, a6, a7); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, - A7 a7, A8 a8) { - return f(a1, a2, a3, a4, a5, a6, a7, a8); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, - A7 a7, A8 a8, A9 a9) { - return f(a1, a2, a3, a4, a5, a6, a7, a8, a9); -} -template -R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, - A7 a7, A8 a8, A9 a9, A10 a10) { - return f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); -} -} // namespace invoke_argument -} // namespace internal - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_0_VALUE_PARAMS()) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args)); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(p0)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_2_VALUE_PARAMS(p0, p1)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_3_VALUE_PARAMS(p0, p1, p2)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4, p5); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4, p5, p6); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8); -} - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); -} - -// Various overloads for ReturnNew(). -// -// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new -// instance of type T, constructed on the heap with constructor arguments -// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_0_VALUE_PARAMS()) { - return new T(); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_1_VALUE_PARAMS(p0)) { - return new T(p0); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_2_VALUE_PARAMS(p0, p1)) { - return new T(p0, p1); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_3_VALUE_PARAMS(p0, p1, p2)) { - return new T(p0, p1, p2); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { - return new T(p0, p1, p2, p3); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { - return new T(p0, p1, p2, p3, p4); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { - return new T(p0, p1, p2, p3, p4, p5); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { - return new T(p0, p1, p2, p3, p4, p5, p6); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { - return new T(p0, p1, p2, p3, p4, p5, p6, p7); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { - return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8); -} - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { - return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); -} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -} // namespace testing - -// Include any custom actions added by the local installation. -// We must include this header at the end to make sure it can use the -// declarations from this file. -#include "gmock/internal/custom/gmock-generated-actions.h" - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h.pump b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h.pump deleted file mode 100644 index 66d9f9d55..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-actions.h.pump +++ /dev/null @@ -1,794 +0,0 @@ -$$ -*- mode: c++; -*- -$$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-actions.h. -$$ -$var n = 10 $$ The maximum arity we support. -$$}} This meta comment fixes auto-indentation in editors. -// 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 Mock - a framework for writing C++ mock classes. -// -// This file implements some commonly used variadic actions. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ - -#include "gmock/gmock-actions.h" -#include "gmock/internal/gmock-port.h" - -namespace testing { -namespace internal { - -// InvokeHelper knows how to unpack an N-tuple and invoke an N-ary -// function or method with the unpacked values, where F is a function -// type that takes N arguments. -template -class InvokeHelper; - - -$range i 0..n -$for i [[ -$range j 1..i -$var types = [[$for j [[, typename A$j]]]] -$var as = [[$for j, [[A$j]]]] -$var args = [[$if i==0 [[]] $else [[ args]]]] -$var gets = [[$for j, [[get<$(j - 1)>(args)]]]] -template -class InvokeHelper > { - public: - template - static R Invoke(Function function, const ::testing::tuple<$as>&$args) { - return function($gets); - } - - template - static R InvokeMethod(Class* obj_ptr, - MethodPtr method_ptr, - const ::testing::tuple<$as>&$args) { - return (obj_ptr->*method_ptr)($gets); - } -}; - - -]] -// An INTERNAL macro for extracting the type of a tuple field. It's -// subject to change without notice - DO NOT USE IN USER CODE! -#define GMOCK_FIELD_(Tuple, N) \ - typename ::testing::tuple_element::type - -$range i 1..n - -// SelectArgs::type is the -// type of an n-ary function whose i-th (1-based) argument type is the -// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple -// type, and whose return type is Result. For example, -// SelectArgs, 0, 3>::type -// is int(bool, long). -// -// SelectArgs::Select(args) -// returns the selected fields (k1, k2, ..., k_n) of args as a tuple. -// For example, -// SelectArgs, 2, 0>::Select( -// ::testing::make_tuple(true, 'a', 2.5)) -// returns tuple (2.5, true). -// -// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be -// in the range [0, $n]. Duplicates are allowed and they don't have -// to be in an ascending or descending order. - -template -class SelectArgs { - public: - typedef Result type($for i, [[GMOCK_FIELD_(ArgumentTuple, k$i)]]); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& args) { - return SelectedArgs($for i, [[get(args)]]); - } -}; - - -$for i [[ -$range j 1..n -$range j1 1..i-1 -template -class SelectArgs { - public: - typedef Result type($for j1, [[GMOCK_FIELD_(ArgumentTuple, k$j1)]]); - typedef typename Function::ArgumentTuple SelectedArgs; - static SelectedArgs Select(const ArgumentTuple& [[]] -$if i == 1 [[/* args */]] $else [[args]]) { - return SelectedArgs($for j1, [[get(args)]]); - } -}; - - -]] -#undef GMOCK_FIELD_ - -$var ks = [[$for i, [[k$i]]]] - -// Implements the WithArgs action. -template -class WithArgsAction { - public: - explicit WithArgsAction(const InnerAction& action) : action_(action) {} - - template - operator Action() const { return MakeAction(new Impl(action_)); } - - private: - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - explicit Impl(const InnerAction& action) : action_(action) {} - - virtual Result Perform(const ArgumentTuple& args) { - return action_.Perform(SelectArgs::Select(args)); - } - - private: - typedef typename SelectArgs::type InnerFunctionType; - - Action action_; - }; - - const InnerAction action_; - - GTEST_DISALLOW_ASSIGN_(WithArgsAction); -}; - -// A macro from the ACTION* family (defined later in this file) -// defines an action that can be used in a mock function. Typically, -// these actions only care about a subset of the arguments of the mock -// function. For example, if such an action only uses the second -// argument, it can be used in any mock function that takes >= 2 -// arguments where the type of the second argument is compatible. -// -// Therefore, the action implementation must be prepared to take more -// arguments than it needs. The ExcessiveArg type is used to -// represent those excessive arguments. In order to keep the compiler -// error messages tractable, we define it in the testing namespace -// instead of testing::internal. However, this is an INTERNAL TYPE -// and subject to change without notice, so a user MUST NOT USE THIS -// TYPE DIRECTLY. -struct ExcessiveArg {}; - -// A helper class needed for implementing the ACTION* macros. -template -class ActionHelper { - public: -$range i 0..n -$for i - -[[ -$var template = [[$if i==0 [[]] $else [[ -$range j 0..i-1 - template <$for j, [[typename A$j]]> -]]]] -$range j 0..i-1 -$var As = [[$for j, [[A$j]]]] -$var as = [[$for j, [[get<$j>(args)]]]] -$range k 1..n-i -$var eas = [[$for k, [[ExcessiveArg()]]]] -$var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]] -$template - static Result Perform(Impl* impl, const ::testing::tuple<$As>& args) { - return impl->template gmock_PerformImpl<$As>(args, $arg_list); - } - -]] -}; - -} // namespace internal - -// Various overloads for Invoke(). - -// WithArgs(an_action) creates an action that passes -// the selected arguments of the mock function to an_action and -// performs it. It serves as an adaptor between actions with -// different argument lists. C++ doesn't support default arguments for -// function templates, so we have to overload it. - -$range i 1..n -$for i [[ -$range j 1..i -template <$for j [[int k$j, ]]typename InnerAction> -inline internal::WithArgsAction -WithArgs(const InnerAction& action) { - return internal::WithArgsAction(action); -} - - -]] -// Creates an action that does actions a1, a2, ..., sequentially in -// each invocation. -$range i 2..n -$for i [[ -$range j 2..i -$var types = [[$for j, [[typename Action$j]]]] -$var Aas = [[$for j [[, Action$j a$j]]]] - -template -$range k 1..i-1 - -inline $for k [[internal::DoBothAction]] - -DoAll(Action1 a1$Aas) { -$if i==2 [[ - - return internal::DoBothAction(a1, a2); -]] $else [[ -$range j2 2..i - - return DoAll(a1, DoAll($for j2, [[a$j2]])); -]] - -} - -]] - -} // namespace testing - -// The ACTION* family of macros can be used in a namespace scope to -// define custom actions easily. The syntax: -// -// ACTION(name) { statements; } -// -// will define an action with the given name that executes the -// statements. The value returned by the statements will be used as -// the return value of the action. Inside the statements, you can -// refer to the K-th (0-based) argument of the mock function by -// 'argK', and refer to its type by 'argK_type'. For example: -// -// ACTION(IncrementArg1) { -// arg1_type temp = arg1; -// return ++(*temp); -// } -// -// allows you to write -// -// ...WillOnce(IncrementArg1()); -// -// You can also refer to the entire argument tuple and its type by -// 'args' and 'args_type', and refer to the mock function type and its -// return type by 'function_type' and 'return_type'. -// -// Note that you don't need to specify the types of the mock function -// arguments. However rest assured that your code is still type-safe: -// you'll get a compiler error if *arg1 doesn't support the ++ -// operator, or if the type of ++(*arg1) isn't compatible with the -// mock function's return type, for example. -// -// Sometimes you'll want to parameterize the action. For that you can use -// another macro: -// -// ACTION_P(name, param_name) { statements; } -// -// For example: -// -// ACTION_P(Add, n) { return arg0 + n; } -// -// will allow you to write: -// -// ...WillOnce(Add(5)); -// -// Note that you don't need to provide the type of the parameter -// either. If you need to reference the type of a parameter named -// 'foo', you can write 'foo_type'. For example, in the body of -// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type -// of 'n'. -// -// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support -// multi-parameter actions. -// -// For the purpose of typing, you can view -// -// ACTION_Pk(Foo, p1, ..., pk) { ... } -// -// as shorthand for -// -// template -// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } -// -// In particular, you can provide the template type arguments -// explicitly when invoking Foo(), as in Foo(5, false); -// although usually you can rely on the compiler to infer the types -// for you automatically. You can assign the result of expression -// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. -// -// You can also overload actions with different numbers of parameters: -// -// ACTION_P(Plus, a) { ... } -// ACTION_P2(Plus, a, b) { ... } -// -// While it's tempting to always use the ACTION* macros when defining -// a new action, you should also consider implementing ActionInterface -// or using MakePolymorphicAction() instead, especially if you need to -// use the action a lot. While these approaches require more work, -// they give you more control on the types of the mock function -// arguments and the action parameters, which in general leads to -// better compiler error messages that pay off in the long run. They -// also allow overloading actions based on parameter types (as opposed -// to just based on the number of parameters). -// -// CAVEAT: -// -// ACTION*() can only be used in a namespace scope. The reason is -// that C++ doesn't yet allow function-local types to be used to -// instantiate templates. The up-coming C++0x standard will fix this. -// Once that's done, we'll consider supporting using ACTION*() inside -// a function. -// -// MORE INFORMATION: -// -// To learn more about using these macros, please search for 'ACTION' -// on http://code.google.com/p/googlemock/wiki/CookBook. - -$range i 0..n -$range k 0..n-1 - -// An internal macro needed for implementing ACTION*(). -#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ - const args_type& args GTEST_ATTRIBUTE_UNUSED_ -$for k [[, \ - arg$k[[]]_type arg$k GTEST_ATTRIBUTE_UNUSED_]] - - -// Sometimes you want to give an action explicit template parameters -// that cannot be inferred from its value parameters. ACTION() and -// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that -// and can be viewed as an extension to ACTION() and ACTION_P*(). -// -// The syntax: -// -// ACTION_TEMPLATE(ActionName, -// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), -// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -// -// defines an action template that takes m explicit template -// parameters and n value parameters. name_i is the name of the i-th -// template parameter, and kind_i specifies whether it's a typename, -// an integral constant, or a template. p_i is the name of the i-th -// value parameter. -// -// Example: -// -// // DuplicateArg(output) converts the k-th argument of the mock -// // function to type T and copies it to *output. -// ACTION_TEMPLATE(DuplicateArg, -// HAS_2_TEMPLATE_PARAMS(int, k, typename, T), -// AND_1_VALUE_PARAMS(output)) { -// *output = T(::testing::get(args)); -// } -// ... -// int n; -// EXPECT_CALL(mock, Foo(_, _)) -// .WillOnce(DuplicateArg<1, unsigned char>(&n)); -// -// To create an instance of an action template, write: -// -// ActionName(v1, ..., v_n) -// -// where the ts are the template arguments and the vs are the value -// arguments. The value argument types are inferred by the compiler. -// If you want to explicitly specify the value argument types, you can -// provide additional template arguments: -// -// ActionName(v1, ..., v_n) -// -// where u_i is the desired type of v_i. -// -// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the -// number of value parameters, but not on the number of template -// parameters. Without the restriction, the meaning of the following -// is unclear: -// -// OverloadedAction(x); -// -// Are we using a single-template-parameter action where 'bool' refers -// to the type of x, or are we using a two-template-parameter action -// where the compiler is asked to infer the type of x? -// -// Implementation notes: -// -// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and -// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for -// implementing ACTION_TEMPLATE. The main trick we use is to create -// new macro invocations when expanding a macro. For example, we have -// -// #define ACTION_TEMPLATE(name, template_params, value_params) -// ... GMOCK_INTERNAL_DECL_##template_params ... -// -// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) -// to expand to -// -// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... -// -// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the -// preprocessor will continue to expand it to -// -// ... typename T ... -// -// This technique conforms to the C++ standard and is portable. It -// allows us to implement action templates using O(N) code, where N is -// the maximum number of template/value parameters supported. Without -// using it, we'd have to devote O(N^2) amount of code to implement all -// combinations of m and n. - -// Declares the template parameters. - -$range j 1..n -$for j [[ -$range m 0..j-1 -#define GMOCK_INTERNAL_DECL_HAS_$j[[]] -_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[kind$m name$m]] - - -]] - -// Lists the template parameters. - -$for j [[ -$range m 0..j-1 -#define GMOCK_INTERNAL_LIST_HAS_$j[[]] -_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[name$m]] - - -]] - -// Declares the types of value parameters. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_DECL_TYPE_AND_$i[[]] -_VALUE_PARAMS($for j, [[p$j]]) $for j [[, typename p$j##_type]] - - -]] - -// Initializes the value parameters. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_INIT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])\ - ($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(gmock_p$j)]] - - -]] - -// Declares the fields for storing the value parameters. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_DEFN_AND_$i[[]] -_VALUE_PARAMS($for j, [[p$j]]) $for j [[p$j##_type p$j; ]] - - -]] - -// Lists the value parameters. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_LIST_AND_$i[[]] -_VALUE_PARAMS($for j, [[p$j]]) $for j, [[p$j]] - - -]] - -// Lists the value parameter types. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_LIST_TYPE_AND_$i[[]] -_VALUE_PARAMS($for j, [[p$j]]) $for j [[, p$j##_type]] - - -]] - -// Declares the value parameters. - -$for i [[ -$range j 0..i-1 -#define GMOCK_INTERNAL_DECL_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] -$for j, [[p$j##_type p$j]] - - -]] - -// The suffix of the class template implementing the action template. -$for i [[ - - -$range j 0..i-1 -#define GMOCK_INTERNAL_COUNT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] -$if i==1 [[P]] $elif i>=2 [[P$i]] -]] - - -// The name of the class template implementing the action template. -#define GMOCK_ACTION_CLASS_(name, value_params)\ - GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) - -$range k 0..n-1 - -#define ACTION_TEMPLATE(name, template_params, value_params)\ - template \ - class GMOCK_ACTION_CLASS_(name, value_params) {\ - public:\ - explicit GMOCK_ACTION_CLASS_(name, value_params)\ - GMOCK_INTERNAL_INIT_##value_params {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template <$for k, [[typename arg$k[[]]_type]]>\ - return_type gmock_PerformImpl(const args_type& args[[]] -$for k [[, arg$k[[]]_type arg$k]]) const;\ - GMOCK_INTERNAL_DEFN_##value_params\ - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(\ - new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ - }\ - GMOCK_INTERNAL_DEFN_##value_params\ - private:\ - GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ - };\ - template \ - inline GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ - GMOCK_INTERNAL_DECL_##value_params) {\ - return GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ - GMOCK_INTERNAL_LIST_##value_params);\ - }\ - template \ - template \ - template \ - typename ::testing::internal::Function::Result\ - GMOCK_ACTION_CLASS_(name, value_params)<\ - GMOCK_INTERNAL_LIST_##template_params\ - GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ - gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -$for i - -[[ -$var template = [[$if i==0 [[]] $else [[ -$range j 0..i-1 - - template <$for j, [[typename p$j##_type]]>\ -]]]] -$var class_name = [[name##Action[[$if i==0 [[]] $elif i==1 [[P]] - $else [[P$i]]]]]] -$range j 0..i-1 -$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] -$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] -$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] -$var param_field_decls = [[$for j -[[ - - p$j##_type p$j;\ -]]]] -$var param_field_decls2 = [[$for j -[[ - - p$j##_type p$j;\ -]]]] -$var params = [[$for j, [[p$j]]]] -$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] -$var typename_arg_types = [[$for k, [[typename arg$k[[]]_type]]]] -$var arg_types_and_names = [[$for k, [[arg$k[[]]_type arg$k]]]] -$var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] - $else [[ACTION_P$i]]]] - -#define $macro_name(name$for j [[, p$j]])\$template - class $class_name {\ - public:\ - [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {}\ - template \ - class gmock_Impl : public ::testing::ActionInterface {\ - public:\ - typedef F function_type;\ - typedef typename ::testing::internal::Function::Result return_type;\ - typedef typename ::testing::internal::Function::ArgumentTuple\ - args_type;\ - [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ - virtual return_type Perform(const args_type& args) {\ - return ::testing::internal::ActionHelper::\ - Perform(this, args);\ - }\ - template <$typename_arg_types>\ - return_type gmock_PerformImpl(const args_type& args, [[]] -$arg_types_and_names) const;\$param_field_decls - private:\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template operator ::testing::Action() const {\ - return ::testing::Action(new gmock_Impl($params));\ - }\$param_field_decls2 - private:\ - GTEST_DISALLOW_ASSIGN_($class_name);\ - };\$template - inline $class_name$param_types name($param_types_and_names) {\ - return $class_name$param_types($params);\ - }\$template - template \ - template <$typename_arg_types>\ - typename ::testing::internal::Function::Result\ - $class_name$param_types::gmock_Impl::gmock_PerformImpl(\ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const -]] -$$ } // This meta comment fixes auto-indentation in Emacs. It won't -$$ // show up in the generated code. - - -namespace testing { - - -// The ACTION*() macros trigger warning C4100 (unreferenced formal -// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in -// the macro definition, as the warnings are generated when the macro -// is expanded and macro expansion cannot contain #pragma. Therefore -// we suppress them here. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4100) -#endif - -// Various overloads for InvokeArgument(). -// -// The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th -// (0-based) argument, which must be a k-ary callable, of the mock -// function, with arguments a1, a2, ..., a_k. -// -// Notes: -// -// 1. The arguments are passed by value by default. If you need to -// pass an argument by reference, wrap it inside ByRef(). For -// example, -// -// InvokeArgument<1>(5, string("Hello"), ByRef(foo)) -// -// passes 5 and string("Hello") by value, and passes foo by -// reference. -// -// 2. If the callable takes an argument by reference but ByRef() is -// not used, it will receive the reference to a copy of the value, -// instead of the original value. For example, when the 0-th -// argument of the mock function takes a const string&, the action -// -// InvokeArgument<0>(string("Hello")) -// -// makes a copy of the temporary string("Hello") object and passes a -// reference of the copy, instead of the original temporary object, -// to the callable. This makes it easy for a user to define an -// InvokeArgument action from temporary values and have it performed -// later. - -namespace internal { -namespace invoke_argument { - -// Appears in InvokeArgumentAdl's argument list to help avoid -// accidental calls to user functions of the same name. -struct AdlTag {}; - -// InvokeArgumentAdl - a helper for InvokeArgument. -// The basic overloads are provided here for generic functors. -// Overloads for other custom-callables are provided in the -// internal/custom/callback-actions.h header. - -$range i 0..n -$for i -[[ -$range j 1..i - -template -R InvokeArgumentAdl(AdlTag, F f[[$for j [[, A$j a$j]]]]) { - return f([[$for j, [[a$j]]]]); -} -]] - -} // namespace invoke_argument -} // namespace internal - -$range i 0..n -$for i [[ -$range j 0..i-1 - -ACTION_TEMPLATE(InvokeArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { - using internal::invoke_argument::InvokeArgumentAdl; - return InvokeArgumentAdl( - internal::invoke_argument::AdlTag(), - ::testing::get(args)$for j [[, p$j]]); -} - -]] - -// Various overloads for ReturnNew(). -// -// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new -// instance of type T, constructed on the heap with constructor arguments -// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. -$range i 0..n -$for i [[ -$range j 0..i-1 -$var ps = [[$for j, [[p$j]]]] - -ACTION_TEMPLATE(ReturnNew, - HAS_1_TEMPLATE_PARAMS(typename, T), - AND_$i[[]]_VALUE_PARAMS($ps)) { - return new T($ps); -} - -]] - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -} // namespace testing - -// Include any custom callback actions added by the local installation. -// We must include this header at the end to make sure it can use the -// declarations from this file. -#include "gmock/internal/custom/gmock-generated-actions.h" - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h deleted file mode 100644 index 4fa5ca948..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h +++ /dev/null @@ -1,1095 +0,0 @@ -// This file was GENERATED by command: -// pump.py gmock-generated-function-mockers.h.pump -// DO NOT EDIT BY HAND!!! - -// 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 Mock - a framework for writing C++ mock classes. -// -// This file implements function mockers of various arities. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ - -#include "gmock/gmock-spec-builders.h" -#include "gmock/internal/gmock-internal-utils.h" - -#if GTEST_HAS_STD_FUNCTION_ -# include -#endif - -namespace testing { -namespace internal { - -template -class FunctionMockerBase; - -// Note: class FunctionMocker really belongs to the ::testing -// namespace. However if we define it in ::testing, MSVC will -// complain when classes in ::testing::internal declare it as a -// friend class template. To workaround this compiler bug, we define -// FunctionMocker in ::testing::internal and import it into ::testing. -template -class FunctionMocker; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With() { - return this->current_spec(); - } - - R Invoke() { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple()); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1) { - this->current_spec().SetMatchers(::testing::make_tuple(m1)); - return this->current_spec(); - } - - R Invoke(A1 a1) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5, A6); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5, - const Matcher& m6) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, - m6)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5, A6, A7); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5, - const Matcher& m6, const Matcher& m7) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, - m6, m7)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5, A6, A7, A8); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5, - const Matcher& m6, const Matcher& m7, const Matcher& m8) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, - m6, m7, m8)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5, - const Matcher& m6, const Matcher& m7, const Matcher& m8, - const Matcher& m9) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, - m6, m7, m8, m9)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9)); - } -}; - -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With(const Matcher& m1, const Matcher& m2, - const Matcher& m3, const Matcher& m4, const Matcher& m5, - const Matcher& m6, const Matcher& m7, const Matcher& m8, - const Matcher& m9, const Matcher& m10) { - this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, - m6, m7, m8, m9, m10)); - return this->current_spec(); - } - - R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, - A10 a10) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9, - a10)); - } -}; - -} // namespace internal - -// The style guide prohibits "using" statements in a namespace scope -// inside a header file. However, the FunctionMocker class template -// is meant to be defined in the ::testing namespace. The following -// line is just a trick for working around a bug in MSVC 8.0, which -// cannot handle it if we define FunctionMocker in ::testing. -using internal::FunctionMocker; - -// GMOCK_RESULT_(tn, F) expands to the result type of function type F. -// We define this as a variadic macro in case F contains unprotected -// commas (the same reason that we use variadic macros in other places -// in this file). -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_RESULT_(tn, ...) \ - tn ::testing::internal::Function<__VA_ARGS__>::Result - -// The type of argument N of the given function type. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG_(tn, N, ...) \ - tn ::testing::internal::Function<__VA_ARGS__>::Argument##N - -// The matcher type for argument N of the given function type. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER_(tn, N, ...) \ - const ::testing::Matcher& - -// The variable for mocking the given method. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER_(arity, constness, Method) \ - GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - ) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 0), \ - this_method_does_not_take_0_arguments); \ - GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(0, constness, Method).Invoke(); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method() constness { \ - GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(0, constness, Method).With(); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 1), \ - this_method_does_not_take_1_argument); \ - GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ - GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 2), \ - this_method_does_not_take_2_arguments); \ - GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ - GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 3), \ - this_method_does_not_take_3_arguments); \ - GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ - GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 4), \ - this_method_does_not_take_4_arguments); \ - GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ - GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 5), \ - this_method_does_not_take_5_arguments); \ - GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ - GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 6), \ - this_method_does_not_take_6_arguments); \ - GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ - GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 7), \ - this_method_does_not_take_7_arguments); \ - GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ - GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 8), \ - this_method_does_not_take_8_arguments); \ - GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ - GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ - GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 9), \ - this_method_does_not_take_9_arguments); \ - GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ - gmock_a9); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ - GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ - GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ - gmock_a9); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \ - Method) - -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ - GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \ - GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ - == 10), \ - this_method_does_not_take_10_arguments); \ - GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ - gmock_a10); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ - GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ - GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ - GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ - GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ - GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ - GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ - GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ - GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \ - GMOCK_MATCHER_(tn, 10, \ - __VA_ARGS__) gmock_a10) constness { \ - GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \ - gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ - gmock_a10); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \ - Method) - -#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__) -#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__) -#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__) -#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__) -#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__) -#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__) -#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__) -#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__) -#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__) -#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__) -#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__) - -#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__) -#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_T(m, ...) \ - GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD1_T(m, ...) \ - GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD2_T(m, ...) \ - GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD3_T(m, ...) \ - GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD4_T(m, ...) \ - GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD5_T(m, ...) \ - GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD6_T(m, ...) \ - GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD7_T(m, ...) \ - GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD8_T(m, ...) \ - GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD9_T(m, ...) \ - GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__) -#define MOCK_CONST_METHOD10_T(m, ...) \ - GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__) - -#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD0_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD1_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD2_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD3_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD4_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD5_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD6_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD7_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD8_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD9_(, , ct, m, __VA_ARGS__) -#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD10_(, , ct, m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__) - -#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__) -#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__) - -// A MockFunction class has one mock method whose type is F. It is -// useful when you just want your test code to emit some messages and -// have Google Mock verify the right messages are sent (and perhaps at -// the right times). For example, if you are exercising code: -// -// Foo(1); -// Foo(2); -// Foo(3); -// -// and want to verify that Foo(1) and Foo(3) both invoke -// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: -// -// TEST(FooTest, InvokesBarCorrectly) { -// MyMock mock; -// MockFunction check; -// { -// InSequence s; -// -// EXPECT_CALL(mock, Bar("a")); -// EXPECT_CALL(check, Call("1")); -// EXPECT_CALL(check, Call("2")); -// EXPECT_CALL(mock, Bar("a")); -// } -// Foo(1); -// check.Call("1"); -// Foo(2); -// check.Call("2"); -// Foo(3); -// } -// -// The expectation spec says that the first Bar("a") must happen -// before check point "1", the second Bar("a") must happen after check -// point "2", and nothing should happen between the two check -// points. The explicit check points make it easy to tell which -// Bar("a") is called by which call to Foo(). -// -// MockFunction can also be used to exercise code that accepts -// std::function callbacks. To do so, use AsStdFunction() method -// to create std::function proxy forwarding to original object's Call. -// Example: -// -// TEST(FooTest, RunsCallbackWithBarArgument) { -// MockFunction callback; -// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); -// Foo(callback.AsStdFunction()); -// } -template -class MockFunction; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD0_T(Call, R()); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this]() -> R { - return this->Call(); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD1_T(Call, R(A0)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0) -> R { - return this->Call(a0); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD2_T(Call, R(A0, A1)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1) -> R { - return this->Call(a0, a1); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD3_T(Call, R(A0, A1, A2)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2) -> R { - return this->Call(a0, a1, a2); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3) -> R { - return this->Call(a0, a1, a2, a3); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) -> R { - return this->Call(a0, a1, a2, a3, a4); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> R { - return this->Call(a0, a1, a2, a3, a4, a5); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) -> R { - return this->Call(a0, a1, a2, a3, a4, a5, a6); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) -> R { - return this->Call(a0, a1, a2, a3, a4, a5, a6, a7); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, - A8 a8) -> R { - return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, - A8 a8, A9 a9) -> R { - return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h.pump b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h.pump deleted file mode 100644 index 811502d0c..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-function-mockers.h.pump +++ /dev/null @@ -1,291 +0,0 @@ -$$ -*- mode: c++; -*- -$$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-function-mockers.h. -$$ -$var n = 10 $$ The maximum arity we support. -// 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 Mock - a framework for writing C++ mock classes. -// -// This file implements function mockers of various arities. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ - -#include "gmock/gmock-spec-builders.h" -#include "gmock/internal/gmock-internal-utils.h" - -#if GTEST_HAS_STD_FUNCTION_ -# include -#endif - -namespace testing { -namespace internal { - -template -class FunctionMockerBase; - -// Note: class FunctionMocker really belongs to the ::testing -// namespace. However if we define it in ::testing, MSVC will -// complain when classes in ::testing::internal declare it as a -// friend class template. To workaround this compiler bug, we define -// FunctionMocker in ::testing::internal and import it into ::testing. -template -class FunctionMocker; - - -$range i 0..n -$for i [[ -$range j 1..i -$var typename_As = [[$for j [[, typename A$j]]]] -$var As = [[$for j, [[A$j]]]] -$var as = [[$for j, [[a$j]]]] -$var Aas = [[$for j, [[A$j a$j]]]] -$var ms = [[$for j, [[m$j]]]] -$var matchers = [[$for j, [[const Matcher& m$j]]]] -template -class FunctionMocker : public - internal::FunctionMockerBase { - public: - typedef R F($As); - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - MockSpec& With($matchers) { - -$if i >= 1 [[ - this->current_spec().SetMatchers(::testing::make_tuple($ms)); - -]] - return this->current_spec(); - } - - R Invoke($Aas) { - // Even though gcc and MSVC don't enforce it, 'this->' is required - // by the C++ standard [14.6.4] here, as the base class type is - // dependent on the template argument (and thus shouldn't be - // looked into when resolving InvokeWith). - return this->InvokeWith(ArgumentTuple($as)); - } -}; - - -]] -} // namespace internal - -// The style guide prohibits "using" statements in a namespace scope -// inside a header file. However, the FunctionMocker class template -// is meant to be defined in the ::testing namespace. The following -// line is just a trick for working around a bug in MSVC 8.0, which -// cannot handle it if we define FunctionMocker in ::testing. -using internal::FunctionMocker; - -// GMOCK_RESULT_(tn, F) expands to the result type of function type F. -// We define this as a variadic macro in case F contains unprotected -// commas (the same reason that we use variadic macros in other places -// in this file). -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_RESULT_(tn, ...) \ - tn ::testing::internal::Function<__VA_ARGS__>::Result - -// The type of argument N of the given function type. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_ARG_(tn, N, ...) \ - tn ::testing::internal::Function<__VA_ARGS__>::Argument##N - -// The matcher type for argument N of the given function type. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MATCHER_(tn, N, ...) \ - const ::testing::Matcher& - -// The variable for mocking the given method. -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_MOCKER_(arity, constness, Method) \ - GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) - - -$for i [[ -$range j 1..i -$var arg_as = [[$for j, \ - [[GMOCK_ARG_(tn, $j, __VA_ARGS__) gmock_a$j]]]] -$var as = [[$for j, [[gmock_a$j]]]] -$var matcher_as = [[$for j, \ - [[GMOCK_MATCHER_(tn, $j, __VA_ARGS__) gmock_a$j]]]] -// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! -#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \ - GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ - $arg_as) constness { \ - GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ - tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value == $i), \ - this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ - GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ - return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \ - } \ - ::testing::MockSpec<__VA_ARGS__>& \ - gmock_##Method($matcher_as) constness { \ - GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \ - return GMOCK_MOCKER_($i, constness, Method).With($as); \ - } \ - mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method) - - -]] -$for i [[ -#define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_CONST_METHOD$i[[]]_T(m, ...) \ - GMOCK_METHOD$i[[]]_(typename, const, , m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD$i[[]]_(, , ct, m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD$i[[]]_(, const, ct, m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD$i[[]]_(typename, , ct, m, __VA_ARGS__) - -]] - - -$for i [[ -#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__) - -]] - -// A MockFunction class has one mock method whose type is F. It is -// useful when you just want your test code to emit some messages and -// have Google Mock verify the right messages are sent (and perhaps at -// the right times). For example, if you are exercising code: -// -// Foo(1); -// Foo(2); -// Foo(3); -// -// and want to verify that Foo(1) and Foo(3) both invoke -// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: -// -// TEST(FooTest, InvokesBarCorrectly) { -// MyMock mock; -// MockFunction check; -// { -// InSequence s; -// -// EXPECT_CALL(mock, Bar("a")); -// EXPECT_CALL(check, Call("1")); -// EXPECT_CALL(check, Call("2")); -// EXPECT_CALL(mock, Bar("a")); -// } -// Foo(1); -// check.Call("1"); -// Foo(2); -// check.Call("2"); -// Foo(3); -// } -// -// The expectation spec says that the first Bar("a") must happen -// before check point "1", the second Bar("a") must happen after check -// point "2", and nothing should happen between the two check -// points. The explicit check points make it easy to tell which -// Bar("a") is called by which call to Foo(). -// -// MockFunction can also be used to exercise code that accepts -// std::function callbacks. To do so, use AsStdFunction() method -// to create std::function proxy forwarding to original object's Call. -// Example: -// -// TEST(FooTest, RunsCallbackWithBarArgument) { -// MockFunction callback; -// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); -// Foo(callback.AsStdFunction()); -// } -template -class MockFunction; - - -$for i [[ -$range j 0..i-1 -$var ArgTypes = [[$for j, [[A$j]]]] -$var ArgNames = [[$for j, [[a$j]]]] -$var ArgDecls = [[$for j, [[A$j a$j]]]] -template -class MockFunction { - public: - MockFunction() {} - - MOCK_METHOD$i[[]]_T(Call, R($ArgTypes)); - -#if GTEST_HAS_STD_FUNCTION_ - std::function AsStdFunction() { - return [this]($ArgDecls) -> R { - return this->Call($ArgNames); - }; - } -#endif // GTEST_HAS_STD_FUNCTION_ - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); -}; - - -]] -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h deleted file mode 100644 index 57056fd91..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h +++ /dev/null @@ -1,2179 +0,0 @@ -// This file was GENERATED by command: -// pump.py gmock-generated-matchers.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. - -// Google Mock - a framework for writing C++ mock classes. -// -// This file implements some commonly used variadic matchers. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ - -#include -#include -#include -#include -#include "gmock/gmock-matchers.h" - -namespace testing { -namespace internal { - -// The type of the i-th (0-based) field of Tuple. -#define GMOCK_FIELD_TYPE_(Tuple, i) \ - typename ::testing::tuple_element::type - -// TupleFields is for selecting fields from a -// tuple of type Tuple. It has two members: -// -// type: a tuple type whose i-th field is the ki-th field of Tuple. -// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. -// -// For example, in class TupleFields, 2, 0>, we have: -// -// type is tuple, and -// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). - -template -class TupleFields; - -// This generic version is used when there are 10 selectors. -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t), - get(t), get(t), get(t), get(t), get(t)); - } -}; - -// The following specialization is used for 0 ~ 9 selectors. - -template -class TupleFields { - public: - typedef ::testing::tuple<> type; - static type GetSelectedFields(const Tuple& /* t */) { - return type(); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t), - get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t), - get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t), - get(t), get(t), get(t)); - } -}; - -template -class TupleFields { - public: - typedef ::testing::tuple type; - static type GetSelectedFields(const Tuple& t) { - return type(get(t), get(t), get(t), get(t), get(t), - get(t), get(t), get(t), get(t)); - } -}; - -#undef GMOCK_FIELD_TYPE_ - -// Implements the Args() matcher. -template -class ArgsMatcherImpl : public MatcherInterface { - public: - // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; - typedef typename internal::TupleFields::type SelectedArgs; - typedef Matcher MonomorphicInnerMatcher; - - template - explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) - : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - - virtual bool MatchAndExplain(ArgsTuple args, - MatchResultListener* listener) const { - const SelectedArgs& selected_args = GetSelectedArgs(args); - if (!listener->IsInterested()) - return inner_matcher_.Matches(selected_args); - - PrintIndices(listener->stream()); - *listener << "are " << PrintToString(selected_args); - - StringMatchResultListener inner_listener; - const bool match = inner_matcher_.MatchAndExplain(selected_args, - &inner_listener); - PrintIfNotEmpty(inner_listener.str(), listener->stream()); - return match; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "are a tuple "; - PrintIndices(os); - inner_matcher_.DescribeTo(os); - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "are a tuple "; - PrintIndices(os); - inner_matcher_.DescribeNegationTo(os); - } - - private: - static SelectedArgs GetSelectedArgs(ArgsTuple args) { - return TupleFields::GetSelectedFields(args); - } - - // Prints the indices of the selected fields. - static void PrintIndices(::std::ostream* os) { - *os << "whose fields ("; - const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 }; - for (int i = 0; i < 10; i++) { - if (indices[i] < 0) - break; - - if (i >= 1) - *os << ", "; - - *os << "#" << indices[i]; - } - *os << ") "; - } - - const MonomorphicInnerMatcher inner_matcher_; - - GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); -}; - -template -class ArgsMatcher { - public: - explicit ArgsMatcher(const InnerMatcher& inner_matcher) - : inner_matcher_(inner_matcher) {} - - template - operator Matcher() const { - return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); - } - - private: - const InnerMatcher inner_matcher_; - - GTEST_DISALLOW_ASSIGN_(ArgsMatcher); -}; - -// A set of metafunctions for computing the result type of AllOf. -// AllOf(m1, ..., mN) returns -// AllOfResultN::type. - -// Although AllOf isn't defined for one argument, AllOfResult1 is defined -// to simplify the implementation. -template -struct AllOfResult1 { - typedef M1 type; -}; - -template -struct AllOfResult2 { - typedef BothOfMatcher< - typename AllOfResult1::type, - typename AllOfResult1::type - > type; -}; - -template -struct AllOfResult3 { - typedef BothOfMatcher< - typename AllOfResult1::type, - typename AllOfResult2::type - > type; -}; - -template -struct AllOfResult4 { - typedef BothOfMatcher< - typename AllOfResult2::type, - typename AllOfResult2::type - > type; -}; - -template -struct AllOfResult5 { - typedef BothOfMatcher< - typename AllOfResult2::type, - typename AllOfResult3::type - > type; -}; - -template -struct AllOfResult6 { - typedef BothOfMatcher< - typename AllOfResult3::type, - typename AllOfResult3::type - > type; -}; - -template -struct AllOfResult7 { - typedef BothOfMatcher< - typename AllOfResult3::type, - typename AllOfResult4::type - > type; -}; - -template -struct AllOfResult8 { - typedef BothOfMatcher< - typename AllOfResult4::type, - typename AllOfResult4::type - > type; -}; - -template -struct AllOfResult9 { - typedef BothOfMatcher< - typename AllOfResult4::type, - typename AllOfResult5::type - > type; -}; - -template -struct AllOfResult10 { - typedef BothOfMatcher< - typename AllOfResult5::type, - typename AllOfResult5::type - > type; -}; - -// A set of metafunctions for computing the result type of AnyOf. -// AnyOf(m1, ..., mN) returns -// AnyOfResultN::type. - -// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined -// to simplify the implementation. -template -struct AnyOfResult1 { - typedef M1 type; -}; - -template -struct AnyOfResult2 { - typedef EitherOfMatcher< - typename AnyOfResult1::type, - typename AnyOfResult1::type - > type; -}; - -template -struct AnyOfResult3 { - typedef EitherOfMatcher< - typename AnyOfResult1::type, - typename AnyOfResult2::type - > type; -}; - -template -struct AnyOfResult4 { - typedef EitherOfMatcher< - typename AnyOfResult2::type, - typename AnyOfResult2::type - > type; -}; - -template -struct AnyOfResult5 { - typedef EitherOfMatcher< - typename AnyOfResult2::type, - typename AnyOfResult3::type - > type; -}; - -template -struct AnyOfResult6 { - typedef EitherOfMatcher< - typename AnyOfResult3::type, - typename AnyOfResult3::type - > type; -}; - -template -struct AnyOfResult7 { - typedef EitherOfMatcher< - typename AnyOfResult3::type, - typename AnyOfResult4::type - > type; -}; - -template -struct AnyOfResult8 { - typedef EitherOfMatcher< - typename AnyOfResult4::type, - typename AnyOfResult4::type - > type; -}; - -template -struct AnyOfResult9 { - typedef EitherOfMatcher< - typename AnyOfResult4::type, - typename AnyOfResult5::type - > type; -}; - -template -struct AnyOfResult10 { - typedef EitherOfMatcher< - typename AnyOfResult5::type, - typename AnyOfResult5::type - > type; -}; - -} // namespace internal - -// Args(a_matcher) matches a tuple if the selected -// fields of it matches a_matcher. C++ doesn't support default -// arguments for function templates, so we have to overload it. -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -template -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - -// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with -// n elements, where the i-th element in the container must -// match the i-th argument in the list. Each argument of -// ElementsAre() can be either a value or a matcher. We support up to -// 10 arguments. -// -// The use of DecayArray in the implementation allows ElementsAre() -// to accept string literals, whose type is const char[N], but we -// want to treat them as const char*. -// -// NOTE: Since ElementsAre() cares about the order of the elements, it -// must not be used with containers whose elements's order is -// undefined (e.g. hash_map). - -inline internal::ElementsAreMatcher< - ::testing::tuple<> > -ElementsAre() { - typedef ::testing::tuple<> Args; - return internal::ElementsAreMatcher(Args()); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type> > -ElementsAre(const T1& e1) { - typedef ::testing::tuple< - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, - e8)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, - e8, e9)); -} - -template -inline internal::ElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, - const T10& e10) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, - e8, e9, e10)); -} - -// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension -// that matches n elements in any order. We support up to n=10 arguments. - -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple<> > -UnorderedElementsAre() { - typedef ::testing::tuple<> Args; - return internal::UnorderedElementsAreMatcher(Args()); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1) { - typedef ::testing::tuple< - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, - e6)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, - e6, e7)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, - e6, e7, e8)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, - e6, e7, e8, e9)); -} - -template -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> > -UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, - const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, - const T10& e10) { - typedef ::testing::tuple< - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type, - typename internal::DecayArray::type> Args; - return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, - e6, e7, e8, e9, e10)); -} - -// AllOf(m1, m2, ..., mk) matches any value that matches all of the given -// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. - -template -inline typename internal::AllOfResult2::type -AllOf(M1 m1, M2 m2) { - return typename internal::AllOfResult2::type( - m1, - m2); -} - -template -inline typename internal::AllOfResult3::type -AllOf(M1 m1, M2 m2, M3 m3) { - return typename internal::AllOfResult3::type( - m1, - ::testing::AllOf(m2, m3)); -} - -template -inline typename internal::AllOfResult4::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4) { - return typename internal::AllOfResult4::type( - ::testing::AllOf(m1, m2), - ::testing::AllOf(m3, m4)); -} - -template -inline typename internal::AllOfResult5::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { - return typename internal::AllOfResult5::type( - ::testing::AllOf(m1, m2), - ::testing::AllOf(m3, m4, m5)); -} - -template -inline typename internal::AllOfResult6::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { - return typename internal::AllOfResult6::type( - ::testing::AllOf(m1, m2, m3), - ::testing::AllOf(m4, m5, m6)); -} - -template -inline typename internal::AllOfResult7::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { - return typename internal::AllOfResult7::type( - ::testing::AllOf(m1, m2, m3), - ::testing::AllOf(m4, m5, m6, m7)); -} - -template -inline typename internal::AllOfResult8::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { - return typename internal::AllOfResult8::type( - ::testing::AllOf(m1, m2, m3, m4), - ::testing::AllOf(m5, m6, m7, m8)); -} - -template -inline typename internal::AllOfResult9::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { - return typename internal::AllOfResult9::type( - ::testing::AllOf(m1, m2, m3, m4), - ::testing::AllOf(m5, m6, m7, m8, m9)); -} - -template -inline typename internal::AllOfResult10::type -AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { - return typename internal::AllOfResult10::type( - ::testing::AllOf(m1, m2, m3, m4, m5), - ::testing::AllOf(m6, m7, m8, m9, m10)); -} - -// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given -// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. - -template -inline typename internal::AnyOfResult2::type -AnyOf(M1 m1, M2 m2) { - return typename internal::AnyOfResult2::type( - m1, - m2); -} - -template -inline typename internal::AnyOfResult3::type -AnyOf(M1 m1, M2 m2, M3 m3) { - return typename internal::AnyOfResult3::type( - m1, - ::testing::AnyOf(m2, m3)); -} - -template -inline typename internal::AnyOfResult4::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) { - return typename internal::AnyOfResult4::type( - ::testing::AnyOf(m1, m2), - ::testing::AnyOf(m3, m4)); -} - -template -inline typename internal::AnyOfResult5::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { - return typename internal::AnyOfResult5::type( - ::testing::AnyOf(m1, m2), - ::testing::AnyOf(m3, m4, m5)); -} - -template -inline typename internal::AnyOfResult6::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { - return typename internal::AnyOfResult6::type( - ::testing::AnyOf(m1, m2, m3), - ::testing::AnyOf(m4, m5, m6)); -} - -template -inline typename internal::AnyOfResult7::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { - return typename internal::AnyOfResult7::type( - ::testing::AnyOf(m1, m2, m3), - ::testing::AnyOf(m4, m5, m6, m7)); -} - -template -inline typename internal::AnyOfResult8::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { - return typename internal::AnyOfResult8::type( - ::testing::AnyOf(m1, m2, m3, m4), - ::testing::AnyOf(m5, m6, m7, m8)); -} - -template -inline typename internal::AnyOfResult9::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { - return typename internal::AnyOfResult9::type( - ::testing::AnyOf(m1, m2, m3, m4), - ::testing::AnyOf(m5, m6, m7, m8, m9)); -} - -template -inline typename internal::AnyOfResult10::type -AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { - return typename internal::AnyOfResult10::type( - ::testing::AnyOf(m1, m2, m3, m4, m5), - ::testing::AnyOf(m6, m7, m8, m9, m10)); -} - -} // namespace testing - - -// The MATCHER* family of macros can be used in a namespace scope to -// define custom matchers easily. -// -// Basic Usage -// =========== -// -// The syntax -// -// MATCHER(name, description_string) { statements; } -// -// defines a matcher with the given name that executes the statements, -// which must return a bool to indicate if the match succeeds. Inside -// the statements, you can refer to the value being matched by 'arg', -// and refer to its type by 'arg_type'. -// -// The description string documents what the matcher does, and is used -// to generate the failure message when the match fails. Since a -// MATCHER() is usually defined in a header file shared by multiple -// C++ source files, we require the description to be a C-string -// literal to avoid possible side effects. It can be empty, in which -// case we'll use the sequence of words in the matcher name as the -// description. -// -// For example: -// -// MATCHER(IsEven, "") { return (arg % 2) == 0; } -// -// allows you to write -// -// // Expects mock_foo.Bar(n) to be called where n is even. -// EXPECT_CALL(mock_foo, Bar(IsEven())); -// -// or, -// -// // Verifies that the value of some_expression is even. -// EXPECT_THAT(some_expression, IsEven()); -// -// If the above assertion fails, it will print something like: -// -// Value of: some_expression -// Expected: is even -// Actual: 7 -// -// where the description "is even" is automatically calculated from the -// matcher name IsEven. -// -// Argument Type -// ============= -// -// Note that the type of the value being matched (arg_type) is -// determined by the context in which you use the matcher and is -// supplied to you by the compiler, so you don't need to worry about -// declaring it (nor can you). This allows the matcher to be -// polymorphic. For example, IsEven() can be used to match any type -// where the value of "(arg % 2) == 0" can be implicitly converted to -// a bool. In the "Bar(IsEven())" example above, if method Bar() -// takes an int, 'arg_type' will be int; if it takes an unsigned long, -// 'arg_type' will be unsigned long; and so on. -// -// Parameterizing Matchers -// ======================= -// -// Sometimes you'll want to parameterize the matcher. For that you -// can use another macro: -// -// MATCHER_P(name, param_name, description_string) { statements; } -// -// For example: -// -// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -// -// will allow you to write: -// -// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -// -// which may lead to this message (assuming n is 10): -// -// Value of: Blah("a") -// Expected: has absolute value 10 -// Actual: -9 -// -// Note that both the matcher description and its parameter are -// printed, making the message human-friendly. -// -// In the matcher definition body, you can write 'foo_type' to -// reference the type of a parameter named 'foo'. For example, in the -// body of MATCHER_P(HasAbsoluteValue, value) above, you can write -// 'value_type' to refer to the type of 'value'. -// -// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to -// support multi-parameter matchers. -// -// Describing Parameterized Matchers -// ================================= -// -// The last argument to MATCHER*() is a string-typed expression. The -// expression can reference all of the matcher's parameters and a -// special bool-typed variable named 'negation'. When 'negation' is -// false, the expression should evaluate to the matcher's description; -// otherwise it should evaluate to the description of the negation of -// the matcher. For example, -// -// using testing::PrintToString; -// -// MATCHER_P2(InClosedRange, low, hi, -// string(negation ? "is not" : "is") + " in range [" + -// PrintToString(low) + ", " + PrintToString(hi) + "]") { -// return low <= arg && arg <= hi; -// } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: is in range [4, 6] -// ... -// Expected: is not in range [2, 4] -// -// If you specify "" as the description, the failure message will -// contain the sequence of words in the matcher name followed by the -// parameter values printed as a tuple. For example, -// -// MATCHER_P2(InClosedRange, low, hi, "") { ... } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: in closed range (4, 6) -// ... -// Expected: not (in closed range (2, 4)) -// -// Types of Matcher Parameters -// =========================== -// -// For the purpose of typing, you can view -// -// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -// -// as shorthand for -// -// template -// FooMatcherPk -// Foo(p1_type p1, ..., pk_type pk) { ... } -// -// When you write Foo(v1, ..., vk), the compiler infers the types of -// the parameters v1, ..., and vk for you. If you are not happy with -// the result of the type inference, you can specify the types by -// explicitly instantiating the template, as in Foo(5, -// false). As said earlier, you don't get to (or need to) specify -// 'arg_type' as that's determined by the context in which the matcher -// is used. You can assign the result of expression Foo(p1, ..., pk) -// to a variable of type FooMatcherPk. This -// can be useful when composing matchers. -// -// While you can instantiate a matcher template with reference types, -// passing the parameters by pointer usually makes your code more -// readable. If, however, you still want to pass a parameter by -// reference, be aware that in the failure message generated by the -// matcher you will see the value of the referenced object but not its -// address. -// -// Explaining Match Results -// ======================== -// -// Sometimes the matcher description alone isn't enough to explain why -// the match has failed or succeeded. For example, when expecting a -// long string, it can be very helpful to also print the diff between -// the expected string and the actual one. To achieve that, you can -// optionally stream additional information to a special variable -// named result_listener, whose type is a pointer to class -// MatchResultListener: -// -// MATCHER_P(EqualsLongString, str, "") { -// if (arg == str) return true; -// -// *result_listener << "the difference: " -/// << DiffStrings(str, arg); -// return false; -// } -// -// Overloading Matchers -// ==================== -// -// You can overload matchers with different numbers of parameters: -// -// MATCHER_P(Blah, a, description_string1) { ... } -// MATCHER_P2(Blah, a, b, description_string2) { ... } -// -// Caveats -// ======= -// -// When defining a new matcher, you should also consider implementing -// MatcherInterface or using MakePolymorphicMatcher(). These -// approaches require more work than the MATCHER* macros, but also -// give you more control on the types of the value being matched and -// the matcher parameters, which may leads to better compiler error -// messages when the matcher is used wrong. They also allow -// overloading matchers based on parameter types (as opposed to just -// based on the number of parameters). -// -// MATCHER*() can only be used in a namespace scope. The reason is -// that C++ doesn't yet allow function-local types to be used to -// instantiate templates. The up-coming C++0x standard will fix this. -// Once that's done, we'll consider supporting using MATCHER*() inside -// a function. -// -// More Information -// ================ -// -// To learn more about using these macros, please search for 'MATCHER' -// on http://code.google.com/p/googlemock/wiki/CookBook. - -#define MATCHER(name, description)\ - class name##Matcher {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl()\ - {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple<>()));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl());\ - }\ - name##Matcher() {\ - }\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##Matcher);\ - };\ - inline name##Matcher name() {\ - return name##Matcher();\ - }\ - template \ - bool name##Matcher::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P(name, p0, description)\ - template \ - class name##MatcherP {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - explicit gmock_Impl(p0##_type gmock_p0)\ - : p0(gmock_p0) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0));\ - }\ - explicit name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ - }\ - p0##_type p0;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ - };\ - template \ - inline name##MatcherP name(p0##_type p0) {\ - return name##MatcherP(p0);\ - }\ - template \ - template \ - bool name##MatcherP::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P2(name, p0, p1, description)\ - template \ - class name##MatcherP2 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\ - : p0(gmock_p0), p1(gmock_p1) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1));\ - }\ - name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ - p1(gmock_p1) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ - };\ - template \ - inline name##MatcherP2 name(p0##_type p0, \ - p1##_type p1) {\ - return name##MatcherP2(p0, p1);\ - }\ - template \ - template \ - bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P3(name, p0, p1, p2, description)\ - template \ - class name##MatcherP3 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, \ - p2)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2));\ - }\ - name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ - };\ - template \ - inline name##MatcherP3 name(p0##_type p0, \ - p1##_type p1, p2##_type p2) {\ - return name##MatcherP3(p0, p1, p2);\ - }\ - template \ - template \ - bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P4(name, p0, p1, p2, p3, description)\ - template \ - class name##MatcherP4 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3));\ - }\ - name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ - };\ - template \ - inline name##MatcherP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ - p3##_type p3) {\ - return name##MatcherP4(p0, \ - p1, p2, p3);\ - }\ - template \ - template \ - bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ - template \ - class name##MatcherP5 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3, p4)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4));\ - }\ - name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, \ - p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ - };\ - template \ - inline name##MatcherP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4) {\ - return name##MatcherP5(p0, p1, p2, p3, p4);\ - }\ - template \ - template \ - bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ - template \ - class name##MatcherP6 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), p5(gmock_p5) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3, p4, p5)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4, p5));\ - }\ - name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ - };\ - template \ - inline name##MatcherP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ - p3##_type p3, p4##_type p4, p5##_type p5) {\ - return name##MatcherP6(p0, p1, p2, p3, p4, p5);\ - }\ - template \ - template \ - bool name##MatcherP6::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ - template \ - class name##MatcherP7 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3, p4, p5, \ - p6)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4, p5, p6));\ - }\ - name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ - p6(gmock_p6) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ - };\ - template \ - inline name##MatcherP7 name(p0##_type p0, p1##_type p1, \ - p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ - p6##_type p6) {\ - return name##MatcherP7(p0, p1, p2, p3, p4, p5, p6);\ - }\ - template \ - template \ - bool name##MatcherP7::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ - template \ - class name##MatcherP8 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, \ - p3, p4, p5, p6, p7)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7));\ - }\ - name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, \ - p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ - };\ - template \ - inline name##MatcherP8 name(p0##_type p0, \ - p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ - p6##_type p6, p7##_type p7) {\ - return name##MatcherP8(p0, p1, p2, p3, p4, p5, \ - p6, p7);\ - }\ - template \ - template \ - bool name##MatcherP8::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ - template \ - class name##MatcherP9 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8));\ - }\ - name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ - p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ - };\ - template \ - inline name##MatcherP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ - p8##_type p8) {\ - return name##MatcherP9(p0, p1, p2, \ - p3, p4, p5, p6, p7, p8);\ - }\ - template \ - template \ - bool name##MatcherP9::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ - template \ - class name##MatcherP10 {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ - p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ - p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ - p9##_type gmock_p9)\ - : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ - p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ - p8(gmock_p8), p9(gmock_p9) {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - p9##_type p9;\ - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ - }\ - name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ - p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ - p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ - p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ - p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ - p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\ - }\ - p0##_type p0;\ - p1##_type p1;\ - p2##_type p2;\ - p3##_type p3;\ - p4##_type p4;\ - p5##_type p5;\ - p6##_type p6;\ - p7##_type p7;\ - p8##_type p8;\ - p9##_type p9;\ - private:\ - GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ - };\ - template \ - inline name##MatcherP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ - p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ - p9##_type p9) {\ - return name##MatcherP10(p0, \ - p1, p2, p3, p4, p5, p6, p7, p8, p9);\ - }\ - template \ - template \ - bool name##MatcherP10::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h.pump b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h.pump deleted file mode 100644 index de30c2c92..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-matchers.h.pump +++ /dev/null @@ -1,672 +0,0 @@ -$$ -*- mode: c++; -*- -$$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-actions.h. -$$ -$var n = 10 $$ The maximum arity we support. -$$ }} This line fixes auto-indentation of the following code in Emacs. -// 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. - -// Google Mock - a framework for writing C++ mock classes. -// -// This file implements some commonly used variadic matchers. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ - -#include -#include -#include -#include -#include "gmock/gmock-matchers.h" - -namespace testing { -namespace internal { - -$range i 0..n-1 - -// The type of the i-th (0-based) field of Tuple. -#define GMOCK_FIELD_TYPE_(Tuple, i) \ - typename ::testing::tuple_element::type - -// TupleFields is for selecting fields from a -// tuple of type Tuple. It has two members: -// -// type: a tuple type whose i-th field is the ki-th field of Tuple. -// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. -// -// For example, in class TupleFields, 2, 0>, we have: -// -// type is tuple, and -// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). - -template -class TupleFields; - -// This generic version is used when there are $n selectors. -template -class TupleFields { - public: - typedef ::testing::tuple<$for i, [[GMOCK_FIELD_TYPE_(Tuple, k$i)]]> type; - static type GetSelectedFields(const Tuple& t) { - return type($for i, [[get(t)]]); - } -}; - -// The following specialization is used for 0 ~ $(n-1) selectors. - -$for i [[ -$$ }}} -$range j 0..i-1 -$range k 0..n-1 - -template -class TupleFields { - public: - typedef ::testing::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; - static type GetSelectedFields(const Tuple& $if i==0 [[/* t */]] $else [[t]]) { - return type($for j, [[get(t)]]); - } -}; - -]] - -#undef GMOCK_FIELD_TYPE_ - -// Implements the Args() matcher. - -$var ks = [[$for i, [[k$i]]]] -template -class ArgsMatcherImpl : public MatcherInterface { - public: - // ArgsTuple may have top-level const or reference modifiers. - typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; - typedef typename internal::TupleFields::type SelectedArgs; - typedef Matcher MonomorphicInnerMatcher; - - template - explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) - : inner_matcher_(SafeMatcherCast(inner_matcher)) {} - - virtual bool MatchAndExplain(ArgsTuple args, - MatchResultListener* listener) const { - const SelectedArgs& selected_args = GetSelectedArgs(args); - if (!listener->IsInterested()) - return inner_matcher_.Matches(selected_args); - - PrintIndices(listener->stream()); - *listener << "are " << PrintToString(selected_args); - - StringMatchResultListener inner_listener; - const bool match = inner_matcher_.MatchAndExplain(selected_args, - &inner_listener); - PrintIfNotEmpty(inner_listener.str(), listener->stream()); - return match; - } - - virtual void DescribeTo(::std::ostream* os) const { - *os << "are a tuple "; - PrintIndices(os); - inner_matcher_.DescribeTo(os); - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "are a tuple "; - PrintIndices(os); - inner_matcher_.DescribeNegationTo(os); - } - - private: - static SelectedArgs GetSelectedArgs(ArgsTuple args) { - return TupleFields::GetSelectedFields(args); - } - - // Prints the indices of the selected fields. - static void PrintIndices(::std::ostream* os) { - *os << "whose fields ("; - const int indices[$n] = { $ks }; - for (int i = 0; i < $n; i++) { - if (indices[i] < 0) - break; - - if (i >= 1) - *os << ", "; - - *os << "#" << indices[i]; - } - *os << ") "; - } - - const MonomorphicInnerMatcher inner_matcher_; - - GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); -}; - -template -class ArgsMatcher { - public: - explicit ArgsMatcher(const InnerMatcher& inner_matcher) - : inner_matcher_(inner_matcher) {} - - template - operator Matcher() const { - return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); - } - - private: - const InnerMatcher inner_matcher_; - - GTEST_DISALLOW_ASSIGN_(ArgsMatcher); -}; - -// A set of metafunctions for computing the result type of AllOf. -// AllOf(m1, ..., mN) returns -// AllOfResultN::type. - -// Although AllOf isn't defined for one argument, AllOfResult1 is defined -// to simplify the implementation. -template -struct AllOfResult1 { - typedef M1 type; -}; - -$range i 1..n - -$range i 2..n -$for i [[ -$range j 2..i -$var m = i/2 -$range k 1..m -$range t m+1..i - -template -struct AllOfResult$i { - typedef BothOfMatcher< - typename AllOfResult$m<$for k, [[M$k]]>::type, - typename AllOfResult$(i-m)<$for t, [[M$t]]>::type - > type; -}; - -]] - -// A set of metafunctions for computing the result type of AnyOf. -// AnyOf(m1, ..., mN) returns -// AnyOfResultN::type. - -// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined -// to simplify the implementation. -template -struct AnyOfResult1 { - typedef M1 type; -}; - -$range i 1..n - -$range i 2..n -$for i [[ -$range j 2..i -$var m = i/2 -$range k 1..m -$range t m+1..i - -template -struct AnyOfResult$i { - typedef EitherOfMatcher< - typename AnyOfResult$m<$for k, [[M$k]]>::type, - typename AnyOfResult$(i-m)<$for t, [[M$t]]>::type - > type; -}; - -]] - -} // namespace internal - -// Args(a_matcher) matches a tuple if the selected -// fields of it matches a_matcher. C++ doesn't support default -// arguments for function templates, so we have to overload it. - -$range i 0..n -$for i [[ -$range j 1..i -template <$for j [[int k$j, ]]typename InnerMatcher> -inline internal::ArgsMatcher -Args(const InnerMatcher& matcher) { - return internal::ArgsMatcher(matcher); -} - - -]] -// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with -// n elements, where the i-th element in the container must -// match the i-th argument in the list. Each argument of -// ElementsAre() can be either a value or a matcher. We support up to -// $n arguments. -// -// The use of DecayArray in the implementation allows ElementsAre() -// to accept string literals, whose type is const char[N], but we -// want to treat them as const char*. -// -// NOTE: Since ElementsAre() cares about the order of the elements, it -// must not be used with containers whose elements's order is -// undefined (e.g. hash_map). - -$range i 0..n -$for i [[ - -$range j 1..i - -$if i>0 [[ - -template <$for j, [[typename T$j]]> -]] - -inline internal::ElementsAreMatcher< - ::testing::tuple< -$for j, [[ - - typename internal::DecayArray::type]]> > -ElementsAre($for j, [[const T$j& e$j]]) { - typedef ::testing::tuple< -$for j, [[ - - typename internal::DecayArray::type]]> Args; - return internal::ElementsAreMatcher(Args($for j, [[e$j]])); -} - -]] - -// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension -// that matches n elements in any order. We support up to n=$n arguments. - -$range i 0..n -$for i [[ - -$range j 1..i - -$if i>0 [[ - -template <$for j, [[typename T$j]]> -]] - -inline internal::UnorderedElementsAreMatcher< - ::testing::tuple< -$for j, [[ - - typename internal::DecayArray::type]]> > -UnorderedElementsAre($for j, [[const T$j& e$j]]) { - typedef ::testing::tuple< -$for j, [[ - - typename internal::DecayArray::type]]> Args; - return internal::UnorderedElementsAreMatcher(Args($for j, [[e$j]])); -} - -]] - -// AllOf(m1, m2, ..., mk) matches any value that matches all of the given -// sub-matchers. AllOf is called fully qualified to prevent ADL from firing. - -$range i 2..n -$for i [[ -$range j 1..i -$var m = i/2 -$range k 1..m -$range t m+1..i - -template <$for j, [[typename M$j]]> -inline typename internal::AllOfResult$i<$for j, [[M$j]]>::type -AllOf($for j, [[M$j m$j]]) { - return typename internal::AllOfResult$i<$for j, [[M$j]]>::type( - $if m == 1 [[m1]] $else [[::testing::AllOf($for k, [[m$k]])]], - $if m+1 == i [[m$i]] $else [[::testing::AllOf($for t, [[m$t]])]]); -} - -]] - -// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given -// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. - -$range i 2..n -$for i [[ -$range j 1..i -$var m = i/2 -$range k 1..m -$range t m+1..i - -template <$for j, [[typename M$j]]> -inline typename internal::AnyOfResult$i<$for j, [[M$j]]>::type -AnyOf($for j, [[M$j m$j]]) { - return typename internal::AnyOfResult$i<$for j, [[M$j]]>::type( - $if m == 1 [[m1]] $else [[::testing::AnyOf($for k, [[m$k]])]], - $if m+1 == i [[m$i]] $else [[::testing::AnyOf($for t, [[m$t]])]]); -} - -]] - -} // namespace testing -$$ } // This Pump meta comment fixes auto-indentation in Emacs. It will not -$$ // show up in the generated code. - - -// The MATCHER* family of macros can be used in a namespace scope to -// define custom matchers easily. -// -// Basic Usage -// =========== -// -// The syntax -// -// MATCHER(name, description_string) { statements; } -// -// defines a matcher with the given name that executes the statements, -// which must return a bool to indicate if the match succeeds. Inside -// the statements, you can refer to the value being matched by 'arg', -// and refer to its type by 'arg_type'. -// -// The description string documents what the matcher does, and is used -// to generate the failure message when the match fails. Since a -// MATCHER() is usually defined in a header file shared by multiple -// C++ source files, we require the description to be a C-string -// literal to avoid possible side effects. It can be empty, in which -// case we'll use the sequence of words in the matcher name as the -// description. -// -// For example: -// -// MATCHER(IsEven, "") { return (arg % 2) == 0; } -// -// allows you to write -// -// // Expects mock_foo.Bar(n) to be called where n is even. -// EXPECT_CALL(mock_foo, Bar(IsEven())); -// -// or, -// -// // Verifies that the value of some_expression is even. -// EXPECT_THAT(some_expression, IsEven()); -// -// If the above assertion fails, it will print something like: -// -// Value of: some_expression -// Expected: is even -// Actual: 7 -// -// where the description "is even" is automatically calculated from the -// matcher name IsEven. -// -// Argument Type -// ============= -// -// Note that the type of the value being matched (arg_type) is -// determined by the context in which you use the matcher and is -// supplied to you by the compiler, so you don't need to worry about -// declaring it (nor can you). This allows the matcher to be -// polymorphic. For example, IsEven() can be used to match any type -// where the value of "(arg % 2) == 0" can be implicitly converted to -// a bool. In the "Bar(IsEven())" example above, if method Bar() -// takes an int, 'arg_type' will be int; if it takes an unsigned long, -// 'arg_type' will be unsigned long; and so on. -// -// Parameterizing Matchers -// ======================= -// -// Sometimes you'll want to parameterize the matcher. For that you -// can use another macro: -// -// MATCHER_P(name, param_name, description_string) { statements; } -// -// For example: -// -// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -// -// will allow you to write: -// -// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -// -// which may lead to this message (assuming n is 10): -// -// Value of: Blah("a") -// Expected: has absolute value 10 -// Actual: -9 -// -// Note that both the matcher description and its parameter are -// printed, making the message human-friendly. -// -// In the matcher definition body, you can write 'foo_type' to -// reference the type of a parameter named 'foo'. For example, in the -// body of MATCHER_P(HasAbsoluteValue, value) above, you can write -// 'value_type' to refer to the type of 'value'. -// -// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to -// support multi-parameter matchers. -// -// Describing Parameterized Matchers -// ================================= -// -// The last argument to MATCHER*() is a string-typed expression. The -// expression can reference all of the matcher's parameters and a -// special bool-typed variable named 'negation'. When 'negation' is -// false, the expression should evaluate to the matcher's description; -// otherwise it should evaluate to the description of the negation of -// the matcher. For example, -// -// using testing::PrintToString; -// -// MATCHER_P2(InClosedRange, low, hi, -// string(negation ? "is not" : "is") + " in range [" + -// PrintToString(low) + ", " + PrintToString(hi) + "]") { -// return low <= arg && arg <= hi; -// } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: is in range [4, 6] -// ... -// Expected: is not in range [2, 4] -// -// If you specify "" as the description, the failure message will -// contain the sequence of words in the matcher name followed by the -// parameter values printed as a tuple. For example, -// -// MATCHER_P2(InClosedRange, low, hi, "") { ... } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: in closed range (4, 6) -// ... -// Expected: not (in closed range (2, 4)) -// -// Types of Matcher Parameters -// =========================== -// -// For the purpose of typing, you can view -// -// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -// -// as shorthand for -// -// template -// FooMatcherPk -// Foo(p1_type p1, ..., pk_type pk) { ... } -// -// When you write Foo(v1, ..., vk), the compiler infers the types of -// the parameters v1, ..., and vk for you. If you are not happy with -// the result of the type inference, you can specify the types by -// explicitly instantiating the template, as in Foo(5, -// false). As said earlier, you don't get to (or need to) specify -// 'arg_type' as that's determined by the context in which the matcher -// is used. You can assign the result of expression Foo(p1, ..., pk) -// to a variable of type FooMatcherPk. This -// can be useful when composing matchers. -// -// While you can instantiate a matcher template with reference types, -// passing the parameters by pointer usually makes your code more -// readable. If, however, you still want to pass a parameter by -// reference, be aware that in the failure message generated by the -// matcher you will see the value of the referenced object but not its -// address. -// -// Explaining Match Results -// ======================== -// -// Sometimes the matcher description alone isn't enough to explain why -// the match has failed or succeeded. For example, when expecting a -// long string, it can be very helpful to also print the diff between -// the expected string and the actual one. To achieve that, you can -// optionally stream additional information to a special variable -// named result_listener, whose type is a pointer to class -// MatchResultListener: -// -// MATCHER_P(EqualsLongString, str, "") { -// if (arg == str) return true; -// -// *result_listener << "the difference: " -/// << DiffStrings(str, arg); -// return false; -// } -// -// Overloading Matchers -// ==================== -// -// You can overload matchers with different numbers of parameters: -// -// MATCHER_P(Blah, a, description_string1) { ... } -// MATCHER_P2(Blah, a, b, description_string2) { ... } -// -// Caveats -// ======= -// -// When defining a new matcher, you should also consider implementing -// MatcherInterface or using MakePolymorphicMatcher(). These -// approaches require more work than the MATCHER* macros, but also -// give you more control on the types of the value being matched and -// the matcher parameters, which may leads to better compiler error -// messages when the matcher is used wrong. They also allow -// overloading matchers based on parameter types (as opposed to just -// based on the number of parameters). -// -// MATCHER*() can only be used in a namespace scope. The reason is -// that C++ doesn't yet allow function-local types to be used to -// instantiate templates. The up-coming C++0x standard will fix this. -// Once that's done, we'll consider supporting using MATCHER*() inside -// a function. -// -// More Information -// ================ -// -// To learn more about using these macros, please search for 'MATCHER' -// on http://code.google.com/p/googlemock/wiki/CookBook. - -$range i 0..n -$for i - -[[ -$var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]] - $else [[MATCHER_P$i]]]] -$var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]] - $else [[P$i]]]]]] -$range j 0..i-1 -$var template = [[$if i==0 [[]] $else [[ - - template <$for j, [[typename p$j##_type]]>\ -]]]] -$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] -$var impl_ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] -$var impl_inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] -$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] -$var params = [[$for j, [[p$j]]]] -$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] -$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] -$var param_field_decls = [[$for j -[[ - - p$j##_type p$j;\ -]]]] -$var param_field_decls2 = [[$for j -[[ - - p$j##_type p$j;\ -]]]] - -#define $macro_name(name$for j [[, p$j]], description)\$template - class $class_name {\ - public:\ - template \ - class gmock_Impl : public ::testing::MatcherInterface {\ - public:\ - [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ - $impl_inits {}\ - virtual bool MatchAndExplain(\ - arg_type arg, ::testing::MatchResultListener* result_listener) const;\ - virtual void DescribeTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(false);\ - }\ - virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ - *gmock_os << FormatDescription(true);\ - }\$param_field_decls - private:\ - ::testing::internal::string FormatDescription(bool negation) const {\ - const ::testing::internal::string gmock_description = (description);\ - if (!gmock_description.empty())\ - return gmock_description;\ - return ::testing::internal::FormatMatcherDescription(\ - negation, #name, \ - ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ - ::testing::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\ - }\ - GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ - };\ - template \ - operator ::testing::Matcher() const {\ - return ::testing::Matcher(\ - new gmock_Impl($params));\ - }\ - [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {\ - }\$param_field_decls2 - private:\ - GTEST_DISALLOW_ASSIGN_($class_name);\ - };\$template - inline $class_name$param_types name($param_types_and_names) {\ - return $class_name$param_types($params);\ - }\$template - template \ - bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ - arg_type arg, \ - ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ - const -]] - - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h deleted file mode 100644 index 4095f4d5b..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h +++ /dev/null @@ -1,397 +0,0 @@ -// This file was GENERATED by command: -// pump.py gmock-generated-nice-strict.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) - -// Implements class templates NiceMock, NaggyMock, and StrictMock. -// -// Given a mock class MockFoo that is created using Google Mock, -// NiceMock is a subclass of MockFoo that allows -// uninteresting calls (i.e. calls to mock methods that have no -// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo -// that prints a warning when an uninteresting call occurs, and -// StrictMock is a subclass of MockFoo that treats all -// uninteresting calls as errors. -// -// Currently a mock is naggy by default, so MockFoo and -// NaggyMock behave like the same. However, we will soon -// switch the default behavior of mocks to be nice, as that in general -// leads to more maintainable tests. When that happens, MockFoo will -// stop behaving like NaggyMock and start behaving like -// NiceMock. -// -// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of -// their respective base class, with up-to 10 arguments. Therefore -// you can write NiceMock(5, "a") to construct a nice mock -// where MockFoo has a constructor that accepts (int, const char*), -// for example. -// -// A known limitation is that NiceMock, NaggyMock, -// and StrictMock only works for mock methods defined using -// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. -// If a mock method is defined in a base class of MockFoo, the "nice" -// or "strict" modifier may not affect it, depending on the compiler. -// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT -// supported. -// -// Another known limitation is that the constructors of the base mock -// cannot have arguments passed by non-const reference, which are -// banned by the Google C++ style guide anyway. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ - -#include "gmock/gmock-spec-builders.h" -#include "gmock/internal/gmock-port.h" - -namespace testing { - -template -class NiceMock : public MockClass { - public: - // We don't factor out the constructor body to a common method, as - // we have to avoid a possible clash with members of MockClass. - NiceMock() { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - // C++ doesn't (yet) allow inheritance of constructors, so we have - // to define it for each arity. - template - explicit NiceMock(const A1& a1) : MockClass(a1) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - template - NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, - const A4& a4) : MockClass(a1, a2, a3, a4) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5) : MockClass(a1, a2, a3, a4, a5) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, - a6, a7) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, - a2, a3, a4, a5, a6, a7, a8) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, - const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, - const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { - ::testing::Mock::AllowUninterestingCalls( - internal::ImplicitCast_(this)); - } - - virtual ~NiceMock() { - ::testing::Mock::UnregisterCallReaction( - internal::ImplicitCast_(this)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); -}; - -template -class NaggyMock : public MockClass { - public: - // We don't factor out the constructor body to a common method, as - // we have to avoid a possible clash with members of MockClass. - NaggyMock() { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - // C++ doesn't (yet) allow inheritance of constructors, so we have - // to define it for each arity. - template - explicit NaggyMock(const A1& a1) : MockClass(a1) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - template - NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, - const A4& a4) : MockClass(a1, a2, a3, a4) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5) : MockClass(a1, a2, a3, a4, a5) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, - a6, a7) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, - a2, a3, a4, a5, a6, a7, a8) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, - const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, - const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { - ::testing::Mock::WarnUninterestingCalls( - internal::ImplicitCast_(this)); - } - - virtual ~NaggyMock() { - ::testing::Mock::UnregisterCallReaction( - internal::ImplicitCast_(this)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock); -}; - -template -class StrictMock : public MockClass { - public: - // We don't factor out the constructor body to a common method, as - // we have to avoid a possible clash with members of MockClass. - StrictMock() { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - // C++ doesn't (yet) allow inheritance of constructors, so we have - // to define it for each arity. - template - explicit StrictMock(const A1& a1) : MockClass(a1) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - template - StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, - const A4& a4) : MockClass(a1, a2, a3, a4) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5) : MockClass(a1, a2, a3, a4, a5) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, - a6, a7) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, - a2, a3, a4, a5, a6, a7, a8) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, - const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - template - StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, - const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { - ::testing::Mock::FailUninterestingCalls( - internal::ImplicitCast_(this)); - } - - virtual ~StrictMock() { - ::testing::Mock::UnregisterCallReaction( - internal::ImplicitCast_(this)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); -}; - -// The following specializations catch some (relatively more common) -// user errors of nesting nice and strict mocks. They do NOT catch -// all possible errors. - -// These specializations are declared but not defined, as NiceMock, -// NaggyMock, and StrictMock cannot be nested. - -template -class NiceMock >; -template -class NiceMock >; -template -class NiceMock >; - -template -class NaggyMock >; -template -class NaggyMock >; -template -class NaggyMock >; - -template -class StrictMock >; -template -class StrictMock >; -template -class StrictMock >; - -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h.pump b/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h.pump deleted file mode 100644 index 3ee1ce7f3..000000000 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-generated-nice-strict.h.pump +++ /dev/null @@ -1,161 +0,0 @@ -$$ -*- mode: c++; -*- -$$ This is a Pump source file. Please use Pump to convert it to -$$ gmock-generated-nice-strict.h. -$$ -$var n = 10 $$ The maximum arity we 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) - -// Implements class templates NiceMock, NaggyMock, and StrictMock. -// -// Given a mock class MockFoo that is created using Google Mock, -// NiceMock is a subclass of MockFoo that allows -// uninteresting calls (i.e. calls to mock methods that have no -// EXPECT_CALL specs), NaggyMock is a subclass of MockFoo -// that prints a warning when an uninteresting call occurs, and -// StrictMock is a subclass of MockFoo that treats all -// uninteresting calls as errors. -// -// Currently a mock is naggy by default, so MockFoo and -// NaggyMock behave like the same. However, we will soon -// switch the default behavior of mocks to be nice, as that in general -// leads to more maintainable tests. When that happens, MockFoo will -// stop behaving like NaggyMock and start behaving like -// NiceMock. -// -// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of -// their respective base class, with up-to $n arguments. Therefore -// you can write NiceMock(5, "a") to construct a nice mock -// where MockFoo has a constructor that accepts (int, const char*), -// for example. -// -// A known limitation is that NiceMock, NaggyMock, -// and StrictMock only works for mock methods defined using -// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. -// If a mock method is defined in a base class of MockFoo, the "nice" -// or "strict" modifier may not affect it, depending on the compiler. -// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT -// supported. -// -// Another known limitation is that the constructors of the base mock -// cannot have arguments passed by non-const reference, which are -// banned by the Google C++ style guide anyway. - -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ - -#include "gmock/gmock-spec-builders.h" -#include "gmock/internal/gmock-port.h" - -namespace testing { - -$range kind 0..2 -$for kind [[ - -$var clazz=[[$if kind==0 [[NiceMock]] - $elif kind==1 [[NaggyMock]] - $else [[StrictMock]]]] - -$var method=[[$if kind==0 [[AllowUninterestingCalls]] - $elif kind==1 [[WarnUninterestingCalls]] - $else [[FailUninterestingCalls]]]] - -template -class $clazz : public MockClass { - public: - // We don't factor out the constructor body to a common method, as - // we have to avoid a possible clash with members of MockClass. - $clazz() { - ::testing::Mock::$method( - internal::ImplicitCast_(this)); - } - - // C++ doesn't (yet) allow inheritance of constructors, so we have - // to define it for each arity. - template - explicit $clazz(const A1& a1) : MockClass(a1) { - ::testing::Mock::$method( - internal::ImplicitCast_(this)); - } - -$range i 2..n -$for i [[ -$range j 1..i - template <$for j, [[typename A$j]]> - $clazz($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { - ::testing::Mock::$method( - internal::ImplicitCast_(this)); - } - - -]] - virtual ~$clazz() { - ::testing::Mock::UnregisterCallReaction( - internal::ImplicitCast_(this)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_($clazz); -}; - -]] - -// The following specializations catch some (relatively more common) -// user errors of nesting nice and strict mocks. They do NOT catch -// all possible errors. - -// These specializations are declared but not defined, as NiceMock, -// NaggyMock, and StrictMock cannot be nested. - -template -class NiceMock >; -template -class NiceMock >; -template -class NiceMock >; - -template -class NaggyMock >; -template -class NaggyMock >; -template -class NaggyMock >; - -template -class StrictMock >; -template -class StrictMock >; -template -class StrictMock >; - -} // namespace testing - -#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ diff --git a/src/libtoast/gtest/googlemock/include/gmock/gmock-matchers.h b/src/libtoast/gtest/googlemock/include/gmock/gmock-matchers.h index 33b37a7a5..628290114 100644 --- a/src/libtoast/gtest/googlemock/include/gmock/gmock-matchers.h +++ b/src/libtoast/gtest/googlemock/include/gmock/gmock-matchers.h @@ -26,36 +26,265 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (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 Mock - a framework for writing C++ mock classes. // -// This file implements some commonly used argument matchers. More +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// std::string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on +// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md +// +// This file also implements some commonly used argument matchers. More // matchers can be defined by the user implementing the // MatcherInterface interface if necessary. +// +// See googletest/include/gtest/gtest-matchers.h for the definition of class +// Matcher, class MatcherInterface, and others. -#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ -#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ -#include #include +#include +#include #include #include +#include #include // NOLINT #include #include +#include #include #include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" #include "gtest/gtest.h" -#if GTEST_HAS_STD_INITIALIZER_LIST_ -# include // NOLINT -- must be after gtest.h +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GMOCK_MAYBE_5046_ 5046 +#else +#define GMOCK_MAYBE_5046_ #endif +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + namespace testing { // To implement a matcher Foo for type T, define: @@ -70,123 +299,13 @@ namespace testing { // ownership management as Matcher objects can now be copied like // plain values. -// MatchResultListener is an abstract class. Its << operator can be -// used by a matcher to explain why a value matches or doesn't match. -// -// TODO(wan@google.com): add method -// bool InterestedInWhy(bool result) const; -// to indicate whether the listener is interested in why the match -// result is 'result'. -class MatchResultListener { - public: - // Creates a listener object with the given underlying ostream. The - // listener does not own the ostream, and does not dereference it - // in the constructor or destructor. - explicit MatchResultListener(::std::ostream* os) : stream_(os) {} - virtual ~MatchResultListener() = 0; // Makes this class abstract. - - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x) { - if (stream_ != NULL) - *stream_ << x; - return *this; - } - - // Returns the underlying ostream. - ::std::ostream* stream() { return stream_; } - - // Returns true iff the listener is interested in an explanation of - // the match result. A matcher's MatchAndExplain() method can use - // this information to avoid generating the explanation when no one - // intends to hear it. - bool IsInterested() const { return stream_ != NULL; } - - private: - ::std::ostream* const stream_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); -}; - -inline MatchResultListener::~MatchResultListener() { -} - -// An instance of a subclass of this knows how to describe itself as a -// matcher. -class MatcherDescriberInterface { - public: - virtual ~MatcherDescriberInterface() {} - - // Describes this matcher to an ostream. The function should print - // a verb phrase that describes the property a value matching this - // matcher should have. The subject of the verb phrase is the value - // being matched. For example, the DescribeTo() method of the Gt(7) - // matcher prints "is greater than 7". - virtual void DescribeTo(::std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. For - // example, if the description of this matcher is "is greater than - // 7", the negated description could be "is not greater than 7". - // You are not required to override this when implementing - // MatcherInterface, but it is highly advised so that your matcher - // can produce good error messages. - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not ("; - DescribeTo(os); - *os << ")"; - } -}; - -// The implementation of a matcher. -template -class MatcherInterface : public MatcherDescriberInterface { - public: - // Returns true iff the matcher matches x; also explains the match - // result to 'listener' if necessary (see the next paragraph), in - // the form of a non-restrictive relative clause ("which ...", - // "whose ...", etc) that describes x. For example, the - // MatchAndExplain() method of the Pointee(...) matcher should - // generate an explanation like "which points to ...". - // - // Implementations of MatchAndExplain() should add an explanation of - // the match result *if and only if* they can provide additional - // information that's not already present (or not obvious) in the - // print-out of x and the matcher's description. Whether the match - // succeeds is not a factor in deciding whether an explanation is - // needed, as sometimes the caller needs to print a failure message - // when the match succeeds (e.g. when the matcher is used inside - // Not()). - // - // For example, a "has at least 10 elements" matcher should explain - // what the actual element count is, regardless of the match result, - // as it is useful information to the reader; on the other hand, an - // "is empty" matcher probably only needs to explain what the actual - // size is when the match fails, as it's redundant to say that the - // size is 0 when the value is already known to be empty. - // - // You should override this method when defining a new matcher. - // - // It's the responsibility of the caller (Google Mock) to guarantee - // that 'listener' is not NULL. This helps to simplify a matcher's - // implementation when it doesn't care about the performance, as it - // can talk to 'listener' without checking its validity first. - // However, in order to implement dummy listeners efficiently, - // listener->stream() may be NULL. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Inherits these methods from MatcherDescriberInterface: - // virtual void DescribeTo(::std::ostream* os) const = 0; - // virtual void DescribeNegationTo(::std::ostream* os) const; -}; - // A match result listener that stores the explanation in a string. class StringMatchResultListener : public MatchResultListener { public: StringMatchResultListener() : MatchResultListener(&ss_) {} // Returns the explanation accumulated so far. - internal::string str() const { return ss_.str(); } + std::string str() const { return ss_.str(); } // Clears the explanation accumulated so far. void Clear() { ss_.str(""); } @@ -194,309 +313,11 @@ class StringMatchResultListener : public MatchResultListener { private: ::std::stringstream ss_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); -}; - -namespace internal { - -struct AnyEq { - template - bool operator()(const A& a, const B& b) const { return a == b; } -}; -struct AnyNe { - template - bool operator()(const A& a, const B& b) const { return a != b; } -}; -struct AnyLt { - template - bool operator()(const A& a, const B& b) const { return a < b; } -}; -struct AnyGt { - template - bool operator()(const A& a, const B& b) const { return a > b; } -}; -struct AnyLe { - template - bool operator()(const A& a, const B& b) const { return a <= b; } -}; -struct AnyGe { - template - bool operator()(const A& a, const B& b) const { return a >= b; } -}; - -// A match result listener that ignores the explanation. -class DummyMatchResultListener : public MatchResultListener { - public: - DummyMatchResultListener() : MatchResultListener(NULL) {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); -}; - -// A match result listener that forwards the explanation to a given -// ostream. The difference between this and MatchResultListener is -// that the former is concrete. -class StreamMatchResultListener : public MatchResultListener { - public: - explicit StreamMatchResultListener(::std::ostream* os) - : MatchResultListener(os) {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); -}; - -// An internal class for implementing Matcher, which will derive -// from it. We put functionalities common to all Matcher -// specializations here to avoid code duplication. -template -class MatcherBase { - public: - // Returns true iff the matcher matches x; also explains the match - // result to 'listener'. - bool MatchAndExplain(T x, MatchResultListener* listener) const { - return impl_->MatchAndExplain(x, listener); - } - - // Returns true iff this matcher matches x. - bool Matches(T x) const { - DummyMatchResultListener dummy; - return MatchAndExplain(x, &dummy); - } - - // Describes this matcher to an ostream. - void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } - - // Describes the negation of this matcher to an ostream. - void DescribeNegationTo(::std::ostream* os) const { - impl_->DescribeNegationTo(os); - } - - // Explains why x matches, or doesn't match, the matcher. - void ExplainMatchResultTo(T x, ::std::ostream* os) const { - StreamMatchResultListener listener(os); - MatchAndExplain(x, &listener); - } - - // Returns the describer for this matcher object; retains ownership - // of the describer, which is only guaranteed to be alive when - // this matcher object is alive. - const MatcherDescriberInterface* GetDescriber() const { - return impl_.get(); - } - - protected: - MatcherBase() {} - - // Constructs a matcher from its implementation. - explicit MatcherBase(const MatcherInterface* impl) - : impl_(impl) {} - - virtual ~MatcherBase() {} - - private: - // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar - // interfaces. The former dynamically allocates a chunk of memory - // to hold the reference count, while the latter tracks all - // references using a circular linked list without allocating - // memory. It has been observed that linked_ptr performs better in - // typical scenarios. However, shared_ptr can out-perform - // linked_ptr when there are many more uses of the copy constructor - // than the default constructor. - // - // If performance becomes a problem, we should see if using - // shared_ptr helps. - ::testing::internal::linked_ptr > impl_; -}; - -} // namespace internal - -// A Matcher is a copyable and IMMUTABLE (except by assignment) -// object that can check whether a value of type T matches. The -// implementation of Matcher is just a linked_ptr to const -// MatcherInterface, so copying is fairly cheap. Don't inherit -// from Matcher! -template -class Matcher : public internal::MatcherBase { - public: - // Constructs a null matcher. Needed for storing Matcher objects in STL - // containers. A default-constructed matcher is not yet initialized. You - // cannot use it until a valid value has been assigned to it. - explicit Matcher() {} // NOLINT - - // Constructs a matcher from its implementation. - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - - // Implicit constructor here allows people to write - // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes - Matcher(T value); // NOLINT -}; - -// The following two specializations allow the user to write str -// instead of Eq(str) and "foo" instead of Eq("foo") when a string -// matcher is expected. -template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { - public: - Matcher() {} - - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - - // Allows the user to write str instead of Eq(str) sometimes, where - // str is a string object. - Matcher(const internal::string& s); // NOLINT - - // Allows the user to write "foo" instead of Eq("foo") sometimes. - Matcher(const char* s); // NOLINT -}; - -template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { - public: - Matcher() {} - - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - - // Allows the user to write str instead of Eq(str) sometimes, where - // str is a string object. - Matcher(const internal::string& s); // NOLINT - - // Allows the user to write "foo" instead of Eq("foo") sometimes. - Matcher(const char* s); // NOLINT -}; - -#if GTEST_HAS_STRING_PIECE_ -// The following two specializations allow the user to write str -// instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece -// matcher is expected. -template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { - public: - Matcher() {} - - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - - // Allows the user to write str instead of Eq(str) sometimes, where - // str is a string object. - Matcher(const internal::string& s); // NOLINT - - // Allows the user to write "foo" instead of Eq("foo") sometimes. - Matcher(const char* s); // NOLINT - - // Allows the user to pass StringPieces directly. - Matcher(StringPiece s); // NOLINT -}; - -template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { - public: - Matcher() {} - - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - - // Allows the user to write str instead of Eq(str) sometimes, where - // str is a string object. - Matcher(const internal::string& s); // NOLINT - - // Allows the user to write "foo" instead of Eq("foo") sometimes. - Matcher(const char* s); // NOLINT - - // Allows the user to pass StringPieces directly. - Matcher(StringPiece s); // NOLINT -}; -#endif // GTEST_HAS_STRING_PIECE_ - -// The PolymorphicMatcher class template makes it easy to implement a -// polymorphic matcher (i.e. a matcher that can match values of more -// than one type, e.g. Eq(n) and NotNull()). -// -// To define a polymorphic matcher, a user should provide an Impl -// class that has a DescribeTo() method and a DescribeNegationTo() -// method, and define a member function (or member function template) -// -// bool MatchAndExplain(const Value& value, -// MatchResultListener* listener) const; -// -// See the definition of NotNull() for a complete example. -template -class PolymorphicMatcher { - public: - explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} - - // Returns a mutable reference to the underlying matcher - // implementation object. - Impl& mutable_impl() { return impl_; } - - // Returns an immutable reference to the underlying matcher - // implementation object. - const Impl& impl() const { return impl_; } - - template - operator Matcher() const { - return Matcher(new MonomorphicImpl(impl_)); - } - - private: - template - class MonomorphicImpl : public MatcherInterface { - public: - explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - - virtual void DescribeTo(::std::ostream* os) const { - impl_.DescribeTo(os); - } - - virtual void DescribeNegationTo(::std::ostream* os) const { - impl_.DescribeNegationTo(os); - } - - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { - return impl_.MatchAndExplain(x, listener); - } - - private: - const Impl impl_; - - GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); - }; - - Impl impl_; - - GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher); + StringMatchResultListener(const StringMatchResultListener&) = delete; + StringMatchResultListener& operator=(const StringMatchResultListener&) = + delete; }; -// Creates a matcher from its implementation. This is easier to use -// than the Matcher constructor as it doesn't require you to -// explicitly write the template argument, e.g. -// -// MakeMatcher(foo); -// vs -// Matcher(foo); -template -inline Matcher MakeMatcher(const MatcherInterface* impl) { - return Matcher(impl); -} - -// Creates a polymorphic matcher from its implementation. This is -// easier to use than the PolymorphicMatcher constructor as it -// doesn't require you to explicitly write the template argument, e.g. -// -// MakePolymorphicMatcher(foo); -// vs -// PolymorphicMatcher(foo); -template -inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { - return PolymorphicMatcher(impl); -} - // Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION // and MUST NOT BE USED IN USER CODE!!! namespace internal { @@ -515,7 +336,7 @@ template class MatcherCastImpl { public: static Matcher Cast(const M& polymorphic_matcher_or_value) { - // M can be a polymorhic matcher, in which case we want to use + // M can be a polymorphic matcher, in which case we want to use // its conversion operator to create Matcher. Or it can be a value // that should be passed to the Matcher's constructor. // @@ -524,28 +345,22 @@ class MatcherCastImpl { // constructor from M (this usually happens when T has an implicit // constructor from any type). // - // It won't work to unconditionally implict_cast + // It won't work to unconditionally implicit_cast // polymorphic_matcher_or_value to Matcher because it won't trigger // a user-defined conversion from M to T if one exists (assuming M is // a value). - return CastImpl( - polymorphic_matcher_or_value, - BooleanConstant< - internal::ImplicitlyConvertible >::value>()); + return CastImpl(polymorphic_matcher_or_value, + std::is_convertible>{}, + std::is_convertible{}); } private: - static Matcher CastImpl(const M& value, BooleanConstant) { - // M can't be implicitly converted to Matcher, so M isn't a polymorphic - // matcher. It must be a value then. Use direct initialization to create - // a matcher. - return Matcher(ImplicitCast_(value)); - } - + template static Matcher CastImpl(const M& polymorphic_matcher_or_value, - BooleanConstant) { + std::true_type /* convertible_to_matcher */, + std::integral_constant) { // M is implicitly convertible to Matcher, which means that either - // M is a polymorhpic matcher or Matcher has an implicit constructor + // M is a polymorphic matcher or Matcher has an implicit constructor // from M. In both cases using the implicit conversion will produce a // matcher. // @@ -554,13 +369,36 @@ class MatcherCastImpl { // (first to create T from M and then to create Matcher from T). return polymorphic_matcher_or_value; } + + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It's a value of a type implicitly convertible to T. Use direct + // initialization to create a matcher. + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::true_type /* convertible_to_T */) { + return Matcher(ImplicitCast_(value)); + } + + // M can't be implicitly converted to either Matcher or T. Attempt to use + // polymorphic matcher Eq(value) in this case. + // + // Note that we first attempt to perform an implicit cast on the value and + // only fall back to the polymorphic Eq() matcher afterwards because the + // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end + // which might be undefined even when Rhs is implicitly convertible to Lhs + // (e.g. std::pair vs. std::pair). + // + // We don't define this method inline as we need the declaration of Eq(). + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::false_type /* convertible_to_T */); }; // This more specialized version is used when MatcherCast()'s argument // is already a Matcher. This only compiles when type T can be // statically converted to type U. template -class MatcherCastImpl > { +class MatcherCastImpl> { public: static Matcher Cast(const Matcher& source_matcher) { return Matcher(new Impl(source_matcher)); @@ -573,33 +411,96 @@ class MatcherCastImpl > { : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { - return source_matcher_.MatchAndExplain(static_cast(x), listener); + bool MatchAndExplain(T x, MatchResultListener* listener) const override { + using FromType = typename std::remove_cv::type>::type>::type; + using ToType = typename std::remove_cv::type>::type>::type; + // Do not allow implicitly converting base*/& to derived*/&. + static_assert( + // Do not trigger if only one of them is a pointer. That implies a + // regular conversion and not a down_cast. + (std::is_pointer::type>::value != + std::is_pointer::type>::value) || + std::is_same::value || + !std::is_base_of::value, + "Can't implicitly convert from to "); + + // Do the cast to `U` explicitly if necessary. + // Otherwise, let implicit conversions do the trick. + using CastType = + typename std::conditional::value, + T&, U>::type; + + return source_matcher_.MatchAndExplain(static_cast(x), + listener); } - virtual void DescribeTo(::std::ostream* os) const { + void DescribeTo(::std::ostream* os) const override { source_matcher_.DescribeTo(os); } - virtual void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(::std::ostream* os) const override { source_matcher_.DescribeNegationTo(os); } private: const Matcher source_matcher_; - - GTEST_DISALLOW_ASSIGN_(Impl); }; }; // This even more specialized version is used for efficiently casting // a matcher to its own type. template -class MatcherCastImpl > { +class MatcherCastImpl> { public: static Matcher Cast(const Matcher& matcher) { return matcher; } }; +// Template specialization for parameterless Matcher. +template +class MatcherBaseImpl { + public: + MatcherBaseImpl() = default; + + template + operator ::testing::Matcher() const { // NOLINT(runtime/explicit) + return ::testing::Matcher(new + typename Derived::template gmock_Impl()); + } +}; + +// Template specialization for Matcher with parameters. +template